Hardening 101: Practical Steps to Secure Systems
Practical system hardening for Linux and Windows - reducing attack surface, configuring firewalls, applying least privilege, and closing the gaps attackers exploit.
On this page
Ground Up: Defender's Playbook
Part 3 of 3
View all parts
- 1Logs and Monitoring: Your First Line of Defense
- 2Incident Response: What Happens When Things Go Wrong
- 3Hardening 101: Practical Steps to Secure Systems
Throughout the Attacker’s Playbook module, we saw how attackers find and exploit weaknesses - SUID misconfigurations, unquoted service paths, default credentials, unnecessary open ports. Every technique relied on something being left in a state it shouldn’t be.
Hardening is the process of reducing a system’s attack surface - eliminating the weaknesses before attackers find them. It’s not about buying more tools. It’s about configuring what you already have.
The Principle: Least Privilege, Minimal Surface
Two ideas drive every hardening decision:
- Least privilege - Every user, process, and service gets the minimum access needed to do its job. Nothing more.
- Minimal attack surface - If you don’t need it, disable it. If it’s not running, it can’t be exploited.
These aren’t abstract concepts. Every hardening action below is one of these two ideas applied to a specific system.
Linux Hardening
User and Access Controls
Disable root SSH login. If attackers brute-force SSH, they’ll target root first.
# Edit SSH config
sudo nano /etc/ssh/sshd_config
# Set these values:
PermitRootLogin no
PasswordAuthentication no # Use SSH keys instead
MaxAuthTries 3
# Restart SSH to apply
sudo systemctl restart sshd
Disabling password authentication entirely and requiring SSH keys eliminates brute-force SSH attacks. Keys are exponentially harder to guess than passwords.
Audit sudo access. Review who has sudo rights and what they can run. As we covered in the privilege escalation post, misconfigured sudo entries are one of the easiest escalation paths.
# See all sudoers configuration
sudo cat /etc/sudoers
sudo ls -la /etc/sudoers.d/
# Check for dangerous entries:
# user ALL=(ALL) NOPASSWD: ALL ← Too broad
# user ALL=(root) NOPASSWD: /usr/bin/vim ← Shell escape possible
Replace broad ALL permissions with specific commands. Never grant sudo for binaries that have shell escapes (check GTFOBins).
Remove or lock unused accounts:
# Find accounts with login shells
grep -v "nologin\|false" /etc/passwd
# Lock an unused account
sudo usermod -L olduser
# Set shell to nologin for service accounts
sudo usermod -s /usr/sbin/nologin serviceaccount
File System Hardening
Audit SUID/SGID binaries. These run with elevated privileges and are common escalation vectors.
# Find all SUID binaries
find / -perm -4000 -type f 2>/dev/null
# Remove SUID from binaries that don't need it
sudo chmod u-s /path/to/unnecessary-suid-binary
Keep SUID only on binaries that require it (passwd, sudo, su, mount). Everything else should be reviewed and likely stripped.
Set proper permissions on sensitive files:
# /etc/shadow should only be readable by root
sudo chmod 600 /etc/shadow
# SSH config and keys
sudo chmod 700 ~/.ssh
sudo chmod 600 ~/.ssh/authorized_keys
sudo chmod 600 ~/.ssh/id_rsa
# Cron job scripts run by root should only be writable by root
sudo chmod 755 /opt/scripts/backup.sh
sudo chown root:root /opt/scripts/backup.sh
Remember from the privilege escalation post - writable cron scripts running as root are a direct path to root access.
Use /tmp mount options:
# In /etc/fstab, mount /tmp with restrictive options
tmpfs /tmp tmpfs defaults,noexec,nosuid,nodev 0 0
noexec prevents executing binaries from /tmp - a common location where attackers drop and run malware.
Network Hardening
Configure the firewall. On Linux, use ufw (simpler) or iptables/nftables (more control).
# UFW - default deny, allow only what's needed
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp # SSH (consider restricting to specific IPs)
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
Default deny incoming means any port you didn’t explicitly open is blocked. This is the opposite of the default configuration on most systems, where everything is allowed.
Disable unnecessary services:
# List running services
systemctl list-units --type=service --state=running
# Disable services you don't need
sudo systemctl disable --now cups # Printing (if not needed)
sudo systemctl disable --now avahi-daemon # mDNS (if not needed)
sudo systemctl disable --now bluetooth # Bluetooth (on servers)
Every running service is an attack surface. A web server doesn’t need Bluetooth or printing services.
Automatic Updates
Unpatched systems are the easiest targets. Automate patching where possible.
# Debian/Ubuntu - enable automatic security updates
sudo apt install unattended-upgrades
sudo dpkg-reconfigure unattended-upgrades
For production servers, use a staged patching approach: test patches on a staging server first, then apply to production on a schedule.
Windows Hardening
Account Security
Rename or disable the default Administrator account:
# Rename the built-in Administrator
Rename-LocalUser -Name "Administrator" -NewName "localadm_custom"
# Or disable it entirely and use a named admin account
Disable-LocalUser -Name "Administrator"
Attackers target the default Administrator account name. Renaming it forces them to enumerate usernames first.
Enforce password policy:
# Using Group Policy (gpedit.msc):
# Computer Configuration → Windows Settings → Security Settings → Account Policies
# Minimum password length: 14
# Password complexity: Enabled
# Account lockout threshold: 5 attempts
# Account lockout duration: 30 minutes
Restrict local admin group:
# Check who's in the local administrators group
net localgroup administrators
# Remove users who don't need local admin
net localgroup administrators unnecessaryuser /delete
Most users don’t need local admin. Removing it prevents malware from running with elevated privileges when a user clicks a phishing link.
Service Hardening
Fix unquoted service paths. As covered in the privilege escalation post, these are a common escalation vector.
# Find unquoted service paths
wmic service get name,pathname,startmode |
findstr /i "auto" |
findstr /i /v "C:\Windows\\" |
findstr /v "\""
# Fix by quoting the path in the registry
# HKLM\SYSTEM\CurrentControlSet\Services\<servicename>\ImagePath
Restrict service account permissions: Services should run with minimum required privileges, not as SYSTEM unless absolutely necessary.
Disable SMBv1:
# SMBv1 is old, vulnerable (WannaCry, EternalBlue), and rarely needed
Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol
Windows Firewall
# Enable Windows Firewall for all profiles
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True
# Set default to block inbound
Set-NetFirewallProfile -DefaultInboundAction Block -DefaultOutboundAction Allow
# Allow specific inbound rules as needed
New-NetFirewallRule -DisplayName "Allow RDP from Management" `
-Direction Inbound -Protocol TCP -LocalPort 3389 `
-RemoteAddress 10.0.0.0/24 -Action Allow
Restrict RDP to specific source IPs. Don’t expose it to the internet - it’s one of the most targeted services for brute-force attacks.
PowerShell Security
PowerShell is the most commonly abused tool by attackers on Windows. Lock it down without breaking legitimate use.
# Enable script block logging (logs every PowerShell command)
# Group Policy: Administrative Templates → Windows PowerShell → Turn on Script Block Logging
# Enable Constrained Language Mode for non-admin users
# This prevents access to .NET types commonly used in attacks
[Environment]::SetEnvironmentVariable('__PSLockdownPolicy', '4', 'Machine')
Install Sysmon for detailed process, network, and file monitoring. It’s free from Microsoft and dramatically improves detection capability:
# Download from Microsoft Sysinternals
# Install with a recommended configuration
sysmon64.exe -accepteula -i sysmonconfig-export.xml
Sysmon logs process creation with command lines, network connections, file hash changes, and more. It’s the single most impactful tool for Windows detection.
Network-Level Hardening
These apply regardless of operating system.
Segmentation
Don’t put everything on one flat network. Segment by function and trust level:
Internet → DMZ (web servers, mail) → Internal network → Sensitive data
↓ ↓
Firewall rules Firewall rules
between each zone between each zone
If a web server in the DMZ is compromised, network segmentation prevents the attacker from directly reaching the database server in the internal network.
DNS Security
- Block DNS over HTTPS (DoH) at the firewall unless your organization manages it - attackers use DoH to bypass DNS-based monitoring
- Use DNS filtering (Pi-hole, Cisco Umbrella) to block known malicious domains
- Monitor DNS queries for anomalies (long subdomain strings indicate DNS tunneling for C2)
Disable Unnecessary Protocols
| Protocol | Action |
|---|---|
| Telnet | Disable everywhere. Use SSH |
| FTP | Replace with SFTP or SCP |
| HTTP (unencrypted) | Redirect to HTTPS |
| LLMNR/NBT-NS | Disable on Windows (used in Responder attacks) |
| WPAD | Disable if not used |
Hardening Benchmarks
Don’t build checklists from scratch. Use established benchmarks:
| Benchmark | Source |
|---|---|
| CIS Benchmarks | Industry standard, available for every major OS and application |
| DISA STIGs | U.S. Department of Defense standards |
| Microsoft Security Baselines | Microsoft’s recommended configurations |
CIS Benchmarks are the most widely used. They provide specific, testable recommendations for everything from Linux to Docker to AWS.
Verification
Hardening means nothing if you don’t verify it. Test your hardening:
# Run CIS benchmark scanner (Linux)
# Tools: Lynis (free), OpenSCAP, CIS-CAT
# Install and run Lynis
sudo apt install lynis
sudo lynis audit system
# Windows - use Microsoft Security Compliance Toolkit
# Or run a vulnerability scan against your own systems
Better yet, run the privilege escalation checks against your own systems. If LinPEAS or WinPEAS finds escalation paths, you have hardening work to do.
The Hardening Mindset
Hardening isn’t a one-time task. It’s ongoing:
- Baseline - Apply hardening when systems are built
- Monitor - Detect configuration drift (settings that change back)
- Audit - Regularly scan for compliance with your baseline
- Update - As new vulnerabilities emerge, adjust hardening
Infrastructure as Code (Ansible, Puppet, Chef) helps enforce hardening consistently across all systems. Define your hardened state as code, and drift is automatically corrected.
What’s Next
Module 6 is complete. You’ve learned the defender’s core skills:
- Logs and monitoring - seeing what’s happening
- Incident response - reacting when things go wrong
- Hardening - preventing things from going wrong in the first place
Next up is Module 7: Getting Started - mapping cybersecurity career paths, building your first lab, and planning your learning journey.
References
- CIS Benchmarks - Hardening standards for all major platforms
- DISA STIGs - DoD security configuration guides
- Lynis - Linux security auditing tool
- Microsoft Sysmon - Windows system monitoring
- NSA Cybersecurity Guidance - Hardening guides from NSA
The best time to harden a system is before it’s deployed. The second best time is right now. Every misconfiguration you fix is one less path an attacker can walk.
Related Articles
Privilege Escalation: From User to Admin
How attackers go from low-privilege access to full system control. Linux and Windows techniques, common misconfigurations, and how defenders detect it.
Reverse Shells Explained: The Complete Foundation
What reverse shells are, why attackers use them, how they work under the hood, and where they fit in the attack chain. The foundation before you touch a terminal.
Authentication Attacks: Passwords, Sessions, and Tokens
How login systems break - brute force, credential stuffing, session hijacking, token flaws, and MFA bypass. The complete beginner's guide to auth attacks.