OSSEC HIDS doesn’t just detect intrusions; it actively rewrites your system’s history to make them invisible to attackers.
Let’s get OSSEC installed and configured on your Linux box. This is the server component that will receive and analyze logs from your agents.
First, the prerequisites. You’ll need gcc, make, and the pcre-devel (or libpcre3-dev on Debian/Ubuntu) package. On RHEL-based systems:
sudo yum update -y
sudo yum install -y gcc make pcre-devel
On Debian/Ubuntu systems:
sudo apt update -y
sudo apt install -y gcc make libpcre3-dev
Now, download the latest OSSEC HIDS source. Head over to the OSSEC website (ossec.net) and grab the tarball. As of this writing, it’s ossec-hids-2.9.5.tar.gz.
wget https://github.com/ossec/ossec-hids/archive/refs/tags/2.9.5.tar.gz -O ossec-hids-2.9.5.tar.gz
tar -xvf ossec-hids-2.9.5.tar.gz
cd ossec-hids-2.9.5
Time to compile and install. The ./install.sh script will guide you through it.
sudo ./install.sh
During the installation, you’ll be asked several questions. For a server installation:
1-Log collection (remote clients, i.e. servers): Choose1. This is crucial for the server to receive logs from agents.3-Local system: Choose3. This makes the server itself an agent, allowing it to monitor its own logs.Enter the full path to the OSSEC installation: The default/var/ossecis fine.Do you want to continue? (y/n):yDo you want to start OSSEC HIDS now? (y/n):y
After installation, you’ll likely need to configure OSSEC to listen for agent connections. Edit the OSSEC configuration file:
sudo nano /var/ossec/etc/ossec.conf
Add the following block within the <ossec_config> tags, before the closing </ossec_config> tag:
<client>
<allow_remote>yes</allow_remote>
</client>
This allow_remote>yes</allow_remote> directive tells the OSSEC server to accept connections from remote agents. Without it, agents will be unable to register.
Restart the OSSEC service to apply the changes:
sudo /var/ossec/bin/ossec-control restart
Now, let’s verify it’s running and listening.
sudo /var/ossec/bin/ossec-control status
You should see outputs like:
OSSEC HIDS running
OSSEC API running
To confirm it’s listening for agent connections on UDP port 514 (the default for syslog and OSSEC agent communication), use netstat or ss:
sudo netstat -tulnp | grep 514
or
sudo ss -tulnp | grep 514
You should see a line indicating ossec-analysisd or ossec listening on 0.0.0.0:514 or :::514.
The next step is to add an agent. On the agent machine (which can be the same server or a different one), you’ll repeat the installation process but choose 2-Local, active, remote agents during the ./install.sh script, and then provide the IP address of your OSSEC server when prompted for the "Server address".
The most surprising true thing about OSSEC is that its default configuration, while good, is often too noisy, leading new users to disable critical checks because they’re overwhelmed by alerts.
Let’s look at a real-time log analysis. On the OSSEC server, you can tail the active response log to see what’s happening when an agent reports an event:
sudo tail -f /var/ossec/logs/active-responses.log
If an agent detects a failed SSH login attempt (and you have the corresponding rule enabled), you might see an entry like this appear in the active-responses.log after a short delay:
2023/10/27 10:30:05 ossec-execd: (1220) Trying to run '/var/ossec/active-responses/bin/host-deny.sh' (uid=0, gid=0).
2023/10/27 10:30:05 ossec-execd: Argument: '192.168.1.100'
2023/10/27 10:30:05 ossec-execd: Argument: 'sshd'
2023/10/27 10:30:05 ossec-execd: Argument: '10'
2023/10/27 10:30:05 ossec-execd: Argument: 'red'
This shows ossec-execd is executing the host-deny.sh script, passing the agent’s IP (192.168.1.100), the rule name (sshd), the number of times the rule triggered (10), and the alert level (red). The host-deny.sh script, by default, adds the offending IP to /etc/hosts.deny or your firewall (like iptables or firewalld) to block further access.
The core of OSSEC’s power lies in its rule engine and decoders. Decoders parse raw log messages into structured fields, and rules then match patterns in those fields to trigger alerts or actions. You can find the default rules in /var/ossec/etc/rules/. For instance, rules related to SSH authentication are often in local_rules.xml or included files like ssh_rules.xml.
You can inspect the OSSEC alert log to see the actual alerts generated:
sudo tail -f /var/ossec/logs/alerts/alerts.log
A typical alert for a brute-force SSH attempt might look like this (truncated):
{
"timestamp": "2023/10/27 10:30:05",
"rule": {
"level": 10,
"description": "SSHD brute force detected.",
"id": "5710",
"firedtimes": 10,
"mail": false,
"groups": ["sshd", " தாக்குதல்"]
},
"agent": {
"id": "001",
"name": "my-agent-name"
},
"decoder": {
"name": "sshd"
},
"full_log": "Oct 27 10:29:55 my-server sshd[12345]: Failed password for invalid user test from 192.168.1.100 port 54321 ssh2",
"predecoder": {
"hostname": "my-agent-name",
"program_name": "sshd",
"pid": "12345"
},
"location": "sshd"
}
This JSON structure shows the rule that fired (id: 5710), the level (level: 10), the agent that sent the log, and the original log message (full_log). The groups field is important for organizing rules.
The one thing most people don’t realize is that OSSEC’s active responses, while powerful, are executed by ossec-execd with root privileges by default. If an active response script has a vulnerability, it could be exploited. It’s good practice to review and, if necessary, restrict the permissions of custom active response scripts or run them as a less privileged user.
The next concept you’ll grapple with is managing false positives, which involves tuning your rules and decoders to accurately reflect your environment without generating excessive noise.