It was 2 AM when the alert fired. A process nobody recognized was consuming 40% CPU on a production server. The on-call engineer stared at the screen and asked the question that haunts every underprepared team: "Has this always been here?" Without a system baseline, there was no way to know—and that uncertainty cost the organization six hours of unnecessary triage. This post walks you through building the documentation that eliminates that doubt entirely.
Why Baselines Matter More Than You Think
A system baseline is a verified, point-in-time snapshot of a system's expected state—its running services, open ports, installed packages, scheduled tasks, file integrity checksums, and configuration parameters. It is not optional documentation. It is the reference frame against which all anomalies are measured.
Without it, your security operations team cannot distinguish between a legitimate configuration change and an indicator of compromise. NIST SP 800-53 (CM-2) explicitly requires organizations to develop, document, and maintain baseline configurations. CIS Controls v8 reinforces this under Control 4 (Secure Configuration of Enterprise Assets and Software).
What to Capture in a Baseline
A useful baseline goes beyond a list of installed software. At minimum, document these layers for every system class:
- Running services and listening ports — What should be running, and on which interfaces
- Installed packages and versions — Including patch levels
- Local user accounts and group memberships — Especially privileged accounts
- Scheduled tasks and cron jobs — Frequently abused persistence mechanisms
- Firewall rules and network configuration — Expected ingress/egress paths
- File integrity hashes — Critical binaries, configuration files, and scripts
- Kernel parameters and security modules — SELinux/AppArmor status, sysctl values
Capturing the Baseline: Practical Examples
Start with what you can script. On a Linux system, a simple baseline capture might look like this:
# Listening services and ports
ss -tulnp > /baselines/$(hostname)_listening_ports_$(date +%F).txt
# Installed packages (RHEL/CentOS)
rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' | sort > /baselines/$(hostname)_packages_$(date +%F).txt
# Local users and groups
getent passwd > /baselines/$(hostname)_users_$(date +%F).txt
getent group > /baselines/$(hostname)_groups_$(date +%F).txt
# Cron jobs for all users
for user in $(cut -f1 -d: /etc/passwd); do
echo "=== $user ===" >> /baselines/$(hostname)_cron_$(date +%F).txt
crontab -l -u "$user" 2>/dev/null >> /baselines/$(hostname)_cron_$(date +%F).txt
done
# SHA-256 hashes of critical binaries
sha256sum /usr/sbin/sshd /usr/bin/sudo /usr/bin/passwd > /baselines/$(hostname)_file_hashes_$(date +%F).txtOn Windows, PowerShell offers equivalent visibility:
# Listening ports and owning processes
Get-NetTCPConnection -State Listen | Select-Object LocalAddress, LocalPort, OwningProcess | Export-Csv "C:\Baselines\listening_ports.csv"
# Installed software
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |
Select-Object DisplayName, DisplayVersion, Publisher | Export-Csv "C:\Baselines\installed_software.csv"
# Scheduled tasks
Get-ScheduledTask | Where-Object {$_.State -ne 'Disabled'} | Export-Csv "C:\Baselines\scheduled_tasks.csv"Maintenance: The Part Everyone Skips
A baseline captured once and never updated is a liability. Systems change—patches are applied, services are added, configurations drift. Build a maintenance cadence:
- Re-baseline after every approved change window. Tie this to your change management process so updates are automatic, not aspirational.
- Diff regularly. Use tools like
diff,AIDE,OSSEC, or commercial solutions like Tripwire to compare current state against the documented baseline weekly. - Version control everything. Store baselines in Git. You gain timestamped history, accountability through commits, and easy diffing between any two points in time.
- Classify by system role. A web server baseline differs from a domain controller baseline. Template by function, customize by instance.
Turning Documentation Into Detection
The real power of baselines emerges when you feed deviations into your SIEM or alerting pipeline. A new listening port that does not match the baseline becomes an alert. An unexpected scheduled task triggers an investigation. Baseline documentation stops being a compliance artifact and becomes a living detection mechanism.
Final Thought
The best incident responders are not the ones who know everything about every system. They are the ones who can quickly determine what changed. Build the baseline. Maintain it ruthlessly. Your future 2 AM self will thank you.
Have questions about system baseline documentation and maintenance? I'm always happy to talk shop — reach out or connect with me on LinkedIn.