Skip to content

OSSEC Host-based Intrusion Detection System Cheat Sheet

Overview

OSSEC is a comprehensive open-source Host-based Intrusion Detection System (HIDS) that provides log analysis, file integrity monitoring, policy monitoring, rootkit detection, real-time alerting, and active response capabilities. It operates in a client-server architecture and is widely used for security monitoring, compliance, and incident detection across diverse IT environments including servers, workstations, and network devices.

⚠️ Note: OSSEC requires proper configuration and rule tuning to minimize false positives. It should be deployed with appropriate log sources and monitoring policies for effective security coverage.

Installation

Server Installation (Ubuntu/Debian)

bash
# Download OSSEC
wget https://github.com/ossec/ossec-hids/archive/3.7.0.tar.gz
tar -xzf 3.7.0.tar.gz
cd ossec-hids-3.7.0

# Install dependencies
sudo apt update
sudo apt install build-essential gcc make libevent-dev zlib1g-dev libssl-dev libpcre2-dev

# Run installation script
sudo ./install.sh

# Installation prompts:
# 1. Language: en
# 2. Installation type: server
# 3. Installation directory: /var/ossec (default)
# 4. Email notification: your-email@domain.com
# 5. SMTP server: localhost
# 6. Run integrity check daemon: y
# 7. Run rootkit detection engine: y
# 8. Enable active response: y
# 9. Enable firewall response: y
# 10. White list IP addresses: your-management-ip

# Start OSSEC
sudo /var/ossec/bin/ossec-control start

Agent Installation

bash
# Download and extract OSSEC
wget https://github.com/ossec/ossec-hids/archive/3.7.0.tar.gz
tar -xzf 3.7.0.tar.gz
cd ossec-hids-3.7.0

# Install dependencies
sudo apt install build-essential gcc make

# Run installation script
sudo ./install.sh

# Installation prompts:
# 1. Language: en
# 2. Installation type: agent
# 3. Installation directory: /var/ossec (default)
# 4. OSSEC server IP: server-ip-address
# 5. Run integrity check daemon: y
# 6. Run rootkit detection engine: y
# 7. Enable active response: y

# Start OSSEC agent
sudo /var/ossec/bin/ossec-control start

Package Installation

bash
# Ubuntu/Debian (using Atomicorp repository)
wget -q -O - https://www.atomicorp.com/RPM-GPG-KEY.atomicorp.txt | sudo apt-key add -
echo "deb https://updates.atomicorp.com/channels/atomic/ubuntu focal main" | sudo tee /etc/apt/sources.list.d/atomic.list
sudo apt update
sudo apt install ossec-hids-server

# CentOS/RHEL/Fedora
sudo dnf install epel-release
sudo dnf install ossec-hids-server

# Start and enable service
sudo systemctl start ossec-hids
sudo systemctl enable ossec-hids

Docker Installation

bash
# Pull OSSEC image
docker pull xetus/ossec-server

# Run OSSEC server
docker run -d --name ossec-server \
  -p 1514:1514/udp \
  -p 1515:1515 \
  -v ossec-data:/var/ossec/data \
  -v ossec-logs:/var/ossec/logs \
  -v ossec-etc:/var/ossec/etc \
  xetus/ossec-server

# Create custom Dockerfile
cat > Dockerfile << 'EOF'
FROM xetus/ossec-server
COPY custom-rules/ /var/ossec/rules/
COPY ossec.conf /var/ossec/etc/
ENTRYPOINT ["/opt/ossec-docker-entrypoint.sh"]
EOF

docker build -t custom-ossec .

Basic Configuration

Server Configuration (/var/ossec/etc/ossec.conf)

xml
<!-- ossec.conf - Main configuration file -->
<ossec_config>
  <global>
    <email_notification>yes</email_notification>
    <email_to>admin@example.com</email_to>
    <smtp_server>localhost</smtp_server>
    <email_from>ossec@example.com</email_from>
    <email_maxperhour>12</email_maxperhour>
    <email_log_source>alerts.log</email_log_source>
    <agents_disconnection_time>600</agents_disconnection_time>
    <agents_disconnection_alert_time>0</agents_disconnection_alert_time>
  </global>

  <rules>
    <include>rules_config.xml</include>
    <include>pam_rules.xml</include>
    <include>sshd_rules.xml</include>
    <include>telnetd_rules.xml</include>
    <include>syslog_rules.xml</include>
    <include>arpwatch_rules.xml</include>
    <include>symantec-av_rules.xml</include>
    <include>symantec-ws_rules.xml</include>
    <include>pix_rules.xml</include>
    <include>named_rules.xml</include>
    <include>smbd_rules.xml</include>
    <include>vsftpd_rules.xml</include>
    <include>pure-ftpd_rules.xml</include>
    <include>proftpd_rules.xml</include>
    <include>ms_ftpd_rules.xml</include>
    <include>ftpd_rules.xml</include>
    <include>hordeimp_rules.xml</include>
    <include>roundcube_rules.xml</include>
    <include>wordpress_rules.xml</include>
    <include>cimserver_rules.xml</include>
    <include>vpopmail_rules.xml</include>
    <include>vmpop3d_rules.xml</include>
    <include>courier_rules.xml</include>
    <include>web_rules.xml</include>
    <include>web_appsec_rules.xml</include>
    <include>apache_rules.xml</include>
    <include>nginx_rules.xml</include>
    <include>php_rules.xml</include>
    <include>mysql_rules.xml</include>
    <include>postgresql_rules.xml</include>
    <include>ids_rules.xml</include>
    <include>squid_rules.xml</include>
    <include>firewall_rules.xml</include>
    <include>cisco-ios_rules.xml</include>
    <include>netscreenfw_rules.xml</include>
    <include>sonicwall_rules.xml</include>
    <include>postfix_rules.xml</include>
    <include>sendmail_rules.xml</include>
    <include>imapd_rules.xml</include>
    <include>mailscanner_rules.xml</include>
    <include>dovecot_rules.xml</include>
    <include>ms-exchange_rules.xml</include>
    <include>racoon_rules.xml</include>
    <include>vpn_concentrator_rules.xml</include>
    <include>spamd_rules.xml</include>
    <include>msauth_rules.xml</include>
    <include>mcafee_av_rules.xml</include>
    <include>trend-osce_rules.xml</include>
    <include>ms-se_rules.xml</include>
    <include>zeus_rules.xml</include>
    <include>solaris_bsm_rules.xml</include>
    <include>vmware_rules.xml</include>
    <include>ms_dhcp_rules.xml</include>
    <include>asterisk_rules.xml</include>
    <include>ossec_rules.xml</include>
    <include>attack_rules.xml</include>
    <include>local_rules.xml</include>
  </rules>

  <syscheck>
    <!-- Frequency that syscheck is executed -- default every 22 hours -->
    <frequency>79200</frequency>
    
    <!-- Directories to check  (perform all possible verifications) -->
    <directories check_all="yes">/etc,/usr/bin,/usr/sbin</directories>
    <directories check_all="yes">/bin,/sbin,/boot</directories>
    
    <!-- Files/directories to ignore -->
    <ignore>/etc/mtab</ignore>
    <ignore>/etc/hosts.deny</ignore>
    <ignore>/etc/mail/statistics</ignore>
    <ignore>/etc/random-seed</ignore>
    <ignore>/etc/random.seed</ignore>
    <ignore>/etc/adjtime</ignore>
    <ignore>/etc/httpd/logs</ignore>
    <ignore>/etc/utmpx</ignore>
    <ignore>/etc/wtmpx</ignore>
    <ignore>/etc/cups/certs</ignore>
    <ignore>/etc/dumpdates</ignore>
    <ignore>/etc/svc/volatile</ignore>
    
    <!-- Check the file, but never compute the diff -->
    <nodiff>/etc/ssl/private.key</nodiff>
  </syscheck>

  <rootcheck>
    <disabled>no</disabled>
    <check_files>yes</check_files>
    <check_trojans>yes</check_trojans>
    <check_dev>yes</check_dev>
    <check_sys>yes</check_sys>
    <check_pids>yes</check_pids>
    <check_ports>yes</check_ports>
    <check_if>yes</check_if>
    
    <!-- Frequency that rootcheck is executed -- default every 22 hours -->
    <frequency>79200</frequency>
    
    <rootkit_files>/var/ossec/etc/shared/rootkit_files.txt</rootkit_files>
    <rootkit_trojans>/var/ossec/etc/shared/rootkit_trojans.txt</rootkit_trojans>
    
    <system_audit>/var/ossec/etc/shared/system_audit_rcl.txt</system_audit>
    <system_audit>/var/ossec/etc/shared/system_audit_ssh.txt</system_audit>
    <system_audit>/var/ossec/etc/shared/cis_debian_linux_rcl.txt</system_audit>
    <system_audit>/var/ossec/etc/shared/cis_rhel_linux_rcl.txt</system_audit>
    <system_audit>/var/ossec/etc/shared/cis_rhel5_linux_rcl.txt</system_audit>
  </rootcheck>

  <global>
    <white_list>127.0.0.1</white_list>
    <white_list>^localhost.localdomain$</white_list>
    <white_list>192.168.1.0/24</white_list>
  </global>

  <remote>
    <connection>secure</connection>
    <port>1514</port>
    <protocol>udp</protocol>
  </remote>

  <alerts>
    <log_alert_level>1</log_alert_level>
    <email_alert_level>7</email_alert_level>
  </alerts>

  <localfile>
    <log_format>syslog</log_format>
    <location>/var/log/messages</location>
  </localfile>

  <localfile>
    <log_format>syslog</log_format>
    <location>/var/log/secure</location>
  </localfile>

  <localfile>
    <log_format>syslog</log_format>
    <location>/var/log/maillog</location>
  </localfile>

  <localfile>
    <log_format>apache</log_format>
    <location>/var/log/httpd/access_log</location>
  </localfile>

  <localfile>
    <log_format>apache</log_format>
    <location>/var/log/httpd/error_log</location>
  </localfile>
</ossec_config>

Agent Configuration

xml
<!-- Agent ossec.conf -->
<ossec_config>
  <client>
    <server-ip>192.168.1.100</server-ip>
    <config-profile>ubuntu, ubuntu18, ubuntu18.04</config-profile>
  </client>

  <client_buffer>
    <disabled>no</disabled>
    <length>5000</length>
    <events_per_second>500</events_per_second>
  </client_buffer>

  <logging>
    <log_alert_level>1</log_alert_level>
  </logging>

  <syscheck>
    <frequency>79200</frequency>
    <directories check_all="yes">/etc,/usr/bin,/usr/sbin</directories>
    <directories check_all="yes">/bin,/sbin</directories>
    
    <ignore>/etc/mtab</ignore>
    <ignore>/etc/hosts.deny</ignore>
    <ignore>/etc/mail/statistics</ignore>
    <ignore>/etc/random-seed</ignore>
    <ignore>/etc/adjtime</ignore>
    <ignore>/etc/httpd/logs</ignore>
    <ignore>/etc/utmpx</ignore>
    <ignore>/etc/wtmpx</ignore>
    <ignore>/etc/cups/certs</ignore>
    <ignore>/etc/dumpdates</ignore>
    
    <nodiff>/etc/ssl/private.key</nodiff>
  </syscheck>

  <rootcheck>
    <disabled>no</disabled>
    <check_files>yes</check_files>
    <check_trojans>yes</check_trojans>
    <check_dev>yes</check_dev>
    <check_sys>yes</check_sys>
    <check_pids>yes</check_pids>
    <check_ports>yes</check_ports>
    <check_if>yes</check_if>
    <frequency>79200</frequency>
  </rootcheck>

  <localfile>
    <log_format>syslog</log_format>
    <location>/var/log/messages</location>
  </localfile>

  <localfile>
    <log_format>syslog</log_format>
    <location>/var/log/secure</location>
  </localfile>

  <localfile>
    <log_format>syslog</log_format>
    <location>/var/log/auth.log</location>
  </localfile>

  <localfile>
    <log_format>apache</log_format>
    <location>/var/log/apache2/access.log</location>
  </localfile>

  <localfile>
    <log_format>apache</log_format>
    <location>/var/log/apache2/error.log</location>
  </localfile>
</ossec_config>

Agent Management

Adding Agents

bash
# On OSSEC server - add agent
sudo /var/ossec/bin/manage_agents

# Interactive menu:
# A) Add an agent (A)
# Agent name: web-server-01
# Agent IP: 192.168.1.10
# Agent ID: 001

# Extract agent key
sudo /var/ossec/bin/manage_agents
# E) Extract key for an agent (E)
# Agent ID: 001

# On agent - import key
sudo /var/ossec/bin/manage_agents
# I) Import key from the server (I)
# Paste the key from server

# Restart OSSEC on both server and agent
sudo /var/ossec/bin/ossec-control restart

Automated Agent Management

bash
#!/bin/bash
# add-ossec-agent.sh

OSSEC_SERVER="192.168.1.100"
AGENT_NAME="$1"
AGENT_IP="$2"

if [ $# -ne 2 ]; then
    echo "Usage: $0 <agent_name> <agent_ip>"
    exit 1
fi

# Add agent on server
expect << EOF
spawn /var/ossec/bin/manage_agents
expect "Choose your action"
send "A\r"
expect "Agent name:"
send "$AGENT_NAME\r"
expect "Agent IP Address:"
send "$AGENT_IP\r"
expect "Agent ID:"
send "\r"
expect "Confirm adding it?"
send "y\r"
expect "Choose your action"
send "Q\r"
EOF

# Get agent ID
AGENT_ID=$(sudo /var/ossec/bin/manage_agents -l | grep "$AGENT_NAME" | awk '{print $2}' | sed 's/,//')

# Extract key
AGENT_KEY=$(expect << EOF
spawn /var/ossec/bin/manage_agents
expect "Choose your action"
send "E\r"
expect "Agent ID:"
send "$AGENT_ID\r"
expect "Choose your action"
send "Q\r"
EOF
)

echo "Agent added successfully!"
echo "Agent ID: $AGENT_ID"
echo "Use this key on the agent:"
echo "$AGENT_KEY" | grep -A 1 "Agent key information"

Agent Status Monitoring

bash
# List all agents
sudo /var/ossec/bin/agent_control -l

# Check specific agent status
sudo /var/ossec/bin/agent_control -i 001

# Get agent statistics
sudo /var/ossec/bin/agent_control -s

# Restart agent remotely
sudo /var/ossec/bin/agent_control -R 001

# Get last received events from agent
sudo /var/ossec/bin/agent_control -L -i 001

# Check agent configuration
sudo /var/ossec/bin/agent_control -i 001 -f

Log Analysis and Monitoring

Real-time Log Monitoring

bash
# Monitor alerts in real-time
tail -f /var/ossec/logs/alerts/alerts.log

# Monitor specific alert levels
tail -f /var/ossec/logs/alerts/alerts.log | grep "Rule: "

# Monitor agent logs
tail -f /var/ossec/logs/ossec.log

# Monitor active response logs
tail -f /var/ossec/logs/active-responses.log

# Monitor firewall logs
tail -f /var/ossec/logs/firewall/firewall.log

Alert Analysis

bash
# Search for specific alerts
grep "Authentication success" /var/ossec/logs/alerts/alerts.log

# Find failed login attempts
grep "Authentication failed" /var/ossec/logs/alerts/alerts.log

# Search by rule ID
grep "Rule: 5715" /var/ossec/logs/alerts/alerts.log

# Search by agent
grep "web-server-01" /var/ossec/logs/alerts/alerts.log

# Count alerts by type
grep -o "Rule: [0-9]*" /var/ossec/logs/alerts/alerts.log | sort | uniq -c | sort -nr

# Find high-level alerts
grep "Level: [89]" /var/ossec/logs/alerts/alerts.log

Log Statistics

bash
#!/bin/bash
# ossec-log-stats.sh

LOG_FILE="/var/ossec/logs/alerts/alerts.log"
DATE=$(date +%Y-%m-%d)

echo "OSSEC Alert Statistics for $DATE"
echo "=================================="

# Total alerts today
TOTAL_ALERTS=$(grep "$DATE" "$LOG_FILE" | wc -l)
echo "Total alerts today: $TOTAL_ALERTS"

# Alerts by level
echo -e "\nAlerts by level:"
grep "$DATE" "$LOG_FILE" | grep -o "Level: [0-9]*" | sort | uniq -c | sort -nr

# Top 10 rules
echo -e "\nTop 10 triggered rules:"
grep "$DATE" "$LOG_FILE" | grep -o "Rule: [0-9]*" | sort | uniq -c | sort -nr | head -10

# Top agents
echo -e "\nTop agents by alert count:"
grep "$DATE" "$LOG_FILE" | grep -o "Agent: [^)]*" | sort | uniq -c | sort -nr | head -10

# Authentication events
AUTH_SUCCESS=$(grep "$DATE" "$LOG_FILE" | grep -c "Authentication success")
AUTH_FAILED=$(grep "$DATE" "$LOG_FILE" | grep -c "Authentication failed")
echo -e "\nAuthentication events:"
echo "Successful logins: $AUTH_SUCCESS"
echo "Failed logins: $AUTH_FAILED"

Custom Rules and Decoders

Custom Rules (/var/ossec/rules/local_rules.xml)

xml
<!-- local_rules.xml - Custom rules -->
<group name="local,syslog,">

  <!-- Custom SSH brute force rule -->
  <rule id="100001" level="10">
    <if_matched_sid>5716</if_matched_sid>
    <same_source_ip />
    <description>SSH brute force attack detected.</description>
    <group>authentication_failures,pci_dss_10.2.4,pci_dss_10.2.5,</group>
  </rule>

  <!-- Custom web attack rule -->
  <rule id="100002" level="12">
    <if_group>web</if_group>
    <url>sql|union|select|insert|delete|drop|create|alter|exec|script</url>
    <description>Web application attack detected.</description>
    <group>attack,pci_dss_10.2.4,</group>
  </rule>

  <!-- Custom file modification rule -->
  <rule id="100003" level="7">
    <if_group>syscheck</if_group>
    <field name="file">/etc/passwd|/etc/shadow|/etc/sudoers</field>
    <description>Critical system file modified.</description>
    <group>syscheck,pci_dss_10.5.5,</group>
  </rule>

  <!-- Custom process monitoring rule -->
  <rule id="100004" level="8">
    <if_group>rootcheck</if_group>
    <match>Rootkit 'rk' detected</match>
    <description>Rootkit detection alert.</description>
    <group>rootcheck,</group>
  </rule>

  <!-- Custom application log rule -->
  <rule id="100005" level="5">
    <decoded_as>custom-app</decoded_as>
    <field name="status">ERROR</field>
    <description>Application error detected.</description>
    <group>application,</group>
  </rule>

  <!-- Custom network connection rule -->
  <rule id="100006" level="6">
    <if_group>firewall</if_group>
    <field name="action">DENY</field>
    <field name="dstport">22|23|3389</field>
    <description>Blocked connection to administrative port.</description>
    <group>firewall,access_denied,</group>
  </rule>

  <!-- Custom compliance rule -->
  <rule id="100007" level="9">
    <if_group>authentication_success</if_group>
    <time>22:00-06:00</time>
    <description>After-hours login detected.</description>
    <group>authentication_success,pci_dss_10.2.5,</group>
  </rule>

</group>

Custom Decoders (/var/ossec/etc/local_decoder.xml)

xml
<!-- local_decoder.xml - Custom decoders -->

<!-- Custom application decoder -->
<decoder name="custom-app">
  <program_name>myapp</program_name>
</decoder>

<decoder name="custom-app-details">
  <parent>custom-app</parent>
  <regex>^(\S+) \[(\S+)\] (\S+): (.+)$</regex>
  <order>timestamp,level,status,message</order>
</decoder>

<!-- Custom firewall decoder -->
<decoder name="custom-firewall">
  <program_name>firewall</program_name>
</decoder>

<decoder name="custom-firewall-details">
  <parent>custom-firewall</parent>
  <regex>^(\S+) (\S+) (\S+) (\S+) (\S+) (\S+) (\S+)$</regex>
  <order>action,protocol,srcip,srcport,dstip,dstport,bytes</order>
</decoder>

<!-- Custom database decoder -->
<decoder name="mysql-custom">
  <program_name>mysqld</program_name>
</decoder>

<decoder name="mysql-custom-details">
  <parent>mysql-custom</parent>
  <regex>^(\d+) (\S+) (\S+) (.+)$</regex>
  <order>id,user,host,query</order>
</decoder>

Active Response

Active Response Configuration

xml
<!-- Active response configuration in ossec.conf -->
<ossec_config>
  <command>
    <name>firewall-drop</name>
    <executable>firewall-drop.sh</executable>
    <expect>srcip</expect>
    <timeout_allowed>yes</timeout_allowed>
  </command>

  <command>
    <name>disable-account</name>
    <executable>disable-account.sh</executable>
    <expect>user</expect>
    <timeout_allowed>yes</timeout_allowed>
  </command>

  <command>
    <name>restart-service</name>
    <executable>restart-service.sh</executable>
    <expect>service</expect>
    <timeout_allowed>no</timeout_allowed>
  </command>

  <active-response>
    <disabled>no</disabled>
    <command>firewall-drop</command>
    <location>local</location>
    <rules_id>100001</rules_id>
    <timeout>600</timeout>
  </active-response>

  <active-response>
    <disabled>no</disabled>
    <command>disable-account</command>
    <location>local</location>
    <rules_id>5716</rules_id>
    <timeout>1800</timeout>
  </active-response>

  <active-response>
    <disabled>no</disabled>
    <command>restart-service</command>
    <location>server</location>
    <rules_id>100005</rules_id>
  </active-response>
</ossec_config>

Custom Active Response Scripts

bash
#!/bin/bash
# /var/ossec/active-response/bin/firewall-drop.sh

LOCAL=`dirname $0`;
cd $LOCAL
cd ../
PWD=`pwd`

# Logging
echo "`date` $0 $1 $2 $3 $4 $5" >> ${PWD}/../logs/active-responses.log

# Getting action and IP
ACTION=$1
USER=$2
IP=$3

case "${ACTION}" in
    add)
        # Block IP using iptables
        /sbin/iptables -I INPUT -s ${IP} -j DROP
        echo "`date` - Blocked IP ${IP}" >> ${PWD}/../logs/active-responses.log
        ;;
    delete)
        # Unblock IP
        /sbin/iptables -D INPUT -s ${IP} -j DROP
        echo "`date` - Unblocked IP ${IP}" >> ${PWD}/../logs/active-responses.log
        ;;
esac

exit 0;
bash
#!/bin/bash
# /var/ossec/active-response/bin/disable-account.sh

LOCAL=`dirname $0`;
cd $LOCAL
cd ../
PWD=`pwd`

# Logging
echo "`date` $0 $1 $2 $3 $4 $5" >> ${PWD}/../logs/active-responses.log

# Getting action and user
ACTION=$1
USER=$2
IP=$3

case "${ACTION}" in
    add)
        # Disable user account
        /usr/sbin/usermod -L ${USER}
        echo "`date` - Disabled account ${USER}" >> ${PWD}/../logs/active-responses.log
        ;;
    delete)
        # Enable user account
        /usr/sbin/usermod -U ${USER}
        echo "`date` - Enabled account ${USER}" >> ${PWD}/../logs/active-responses.log
        ;;
esac

exit 0;
bash
#!/bin/bash
# /var/ossec/active-response/bin/restart-service.sh

LOCAL=`dirname $0`;
cd $LOCAL
cd ../
PWD=`pwd`

# Logging
echo "`date` $0 $1 $2 $3 $4 $5" >> ${PWD}/../logs/active-responses.log

# Getting action and service
ACTION=$1
USER=$2
IP=$3
SERVICE=$4

case "${ACTION}" in
    add)
        # Restart service
        /bin/systemctl restart ${SERVICE}
        echo "`date` - Restarted service ${SERVICE}" >> ${PWD}/../logs/active-responses.log
        ;;
esac

exit 0;

Integration and Automation

ELK Stack Integration

bash
#!/bin/bash
# ossec-to-elasticsearch.sh

OSSEC_LOG="/var/ossec/logs/alerts/alerts.log"
ELASTICSEARCH_URL="http://localhost:9200"
INDEX_NAME="ossec-$(date +%Y.%m.%d)"

# Function to parse OSSEC alert
parse_ossec_alert() {
    local alert_file="$1"
    
    python3 << EOF
import json
import re
from datetime import datetime

with open('$alert_file', 'r') as f:
    content = f.read()

# Parse OSSEC alert format
alerts = content.split('** Alert')
for alert in alerts[1:]:  # Skip first empty element
    lines = alert.strip().split('\n')
    
    alert_data = {}
    for line in lines:
        if 'Rule:' in line:
            alert_data['rule_id'] = re.search(r'Rule: (\d+)', line).group(1)
            alert_data['rule_level'] = re.search(r'level (\d+)', line).group(1)
        elif 'Agent:' in line:
            alert_data['agent'] = line.split('Agent: ')[1].split(' ')[0]
        elif 'Location:' in line:
            alert_data['location'] = line.split('Location: ')[1]
        elif line.startswith('20'):  # Timestamp line
            alert_data['timestamp'] = line
    
    # Send to Elasticsearch
    if alert_data:
        print(json.dumps(alert_data))
EOF
}

# Monitor and send alerts
tail -F "$OSSEC_LOG" | while read line; do
    if [[ "$line" == "** Alert"* ]]; then
        # Process complete alert
        temp_file=$(mktemp)
        echo "$line" > "$temp_file"
        
        # Read until next alert or timeout
        timeout 5 bash -c "
            while read next_line; do
                echo \"\$next_line\" >> \"$temp_file\"
                if [[ \"\$next_line\" == \"** Alert\"* ]]; then
                    break
                fi
            done
        "
        
        # Parse and send to Elasticsearch
        alert_json=$(parse_ossec_alert "$temp_file")
        if [ -n "$alert_json" ]; then
            curl -s -H "Content-Type: application/json" \
                 -X POST "$ELASTICSEARCH_URL/$INDEX_NAME/_doc" \
                 -d "$alert_json"
        fi
        
        rm "$temp_file"
    fi
done

Splunk Integration

bash
# /opt/splunk/etc/apps/ossec/local/inputs.conf
[monitor:///var/ossec/logs/alerts/alerts.log]
disabled = false
sourcetype = ossec:alert
index = security

[monitor:///var/ossec/logs/ossec.log]
disabled = false
sourcetype = ossec:system
index = security

[monitor:///var/ossec/logs/active-responses.log]
disabled = false
sourcetype = ossec:active_response
index = security

SIEM Integration Script

python
#!/usr/bin/env python3
# ossec-siem-integration.py

import re
import time
import json
import requests
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

class OSSECLogHandler(FileSystemEventHandler):
    def __init__(self, siem_endpoint, api_key):
        self.siem_endpoint = siem_endpoint
        self.api_key = api_key
        self.current_alert = []
        self.in_alert = False
    
    def on_modified(self, event):
        if event.src_path.endswith('alerts.log'):
            self.process_alerts(event.src_path)
    
    def process_alerts(self, log_path):
        """Process OSSEC alerts"""
        try:
            with open(log_path, 'r') as f:
                f.seek(0, 2)  # Go to end of file
                
                while True:
                    line = f.readline()
                    if not line:
                        time.sleep(0.1)
                        continue
                    
                    if line.startswith('** Alert'):
                        if self.current_alert:
                            self.send_alert_to_siem(self.current_alert)
                        
                        self.current_alert = [line.strip()]
                        self.in_alert = True
                    elif self.in_alert:
                        self.current_alert.append(line.strip())
                        
                        # Check if alert is complete
                        if line.strip() == '' and len(self.current_alert) > 5:
                            self.send_alert_to_siem(self.current_alert)
                            self.current_alert = []
                            self.in_alert = False
        
        except Exception as e:
            print(f"Error processing alerts: {e}")
    
    def parse_alert(self, alert_lines):
        """Parse OSSEC alert format"""
        alert_data = {
            'source': 'ossec',
            'raw_alert': '\n'.join(alert_lines)
        }
        
        for line in alert_lines:
            if 'Rule:' in line:
                match = re.search(r'Rule: (\d+) \(level (\d+)\) -> (.+)', line)
                if match:
                    alert_data['rule_id'] = match.group(1)
                    alert_data['rule_level'] = int(match.group(2))
                    alert_data['rule_description'] = match.group(3)
            
            elif line.startswith('20'):  # Timestamp
                alert_data['timestamp'] = line
            
            elif 'Agent:' in line:
                match = re.search(r'Agent: ([^)]+)', line)
                if match:
                    alert_data['agent'] = match.group(1)
            
            elif 'Location:' in line:
                alert_data['location'] = line.split('Location: ')[1]
            
            elif 'User:' in line:
                match = re.search(r'User: (\S+)', line)
                if match:
                    alert_data['user'] = match.group(1)
            
            elif 'Src IP:' in line:
                match = re.search(r'Src IP: (\S+)', line)
                if match:
                    alert_data['src_ip'] = match.group(1)
        
        return alert_data
    
    def send_alert_to_siem(self, alert_lines):
        """Send parsed alert to SIEM"""
        try:
            alert_data = self.parse_alert(alert_lines)
            
            response = requests.post(
                self.siem_endpoint,
                json=alert_data,
                headers={
                    'Content-Type': 'application/json',
                    'Authorization': f'Bearer {self.api_key}'
                },
                timeout=5
            )
            response.raise_for_status()
            
            print(f"Sent alert to SIEM: Rule {alert_data.get('rule_id', 'Unknown')}")
        
        except requests.RequestException as e:
            print(f"Error sending to SIEM: {e}")
        except Exception as e:
            print(f"Error processing alert: {e}")

def main():
    log_directory = "/var/ossec/logs/alerts"
    siem_endpoint = "https://your-siem.com/api/events"
    api_key = "your-api-key"
    
    event_handler = OSSECLogHandler(siem_endpoint, api_key)
    observer = Observer()
    observer.schedule(event_handler, log_directory, recursive=False)
    
    observer.start()
    print(f"Monitoring OSSEC alerts in {log_directory}")
    
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    
    observer.join()

if __name__ == "__main__":
    main()

Performance Tuning and Optimization

Server Performance Tuning

xml
<!-- Performance optimization in ossec.conf -->
<ossec_config>
  <global>
    <logall>no</logall>
    <logall_json>no</logall_json>
    <email_maxperhour>12</email_maxperhour>
    <agents_disconnection_time>600</agents_disconnection_time>
    <agents_disconnection_alert_time>0</agents_disconnection_alert_time>
  </global>

  <alerts>
    <log_alert_level>3</log_alert_level>
    <email_alert_level>7</email_alert_level>
    <use_geoip>yes</use_geoip>
  </alerts>

  <logging>
    <log_alert_level>1</log_alert_level>
    <log_format>plain</log_format>
  </logging>
</ossec_config>

Database Integration

bash
# Install MySQL support
sudo apt install mysql-server mysql-client libmysqlclient-dev

# Recompile OSSEC with database support
cd ossec-hids-3.7.0
make setdb
sudo make install

# Configure database in ossec.conf
cat >> /var/ossec/etc/ossec.conf << 'EOF'
<database_output>
  <hostname>localhost</hostname>
  <username>ossec</username>
  <password>ossec_password</password>
  <database>ossec</database>
  <type>mysql</type>
</database_output>
EOF

# Create database and tables
mysql -u root -p << 'EOF'
CREATE DATABASE ossec;
CREATE USER 'ossec'@'localhost' IDENTIFIED BY 'ossec_password';
GRANT ALL PRIVILEGES ON ossec.* TO 'ossec'@'localhost';
FLUSH PRIVILEGES;
EOF

# Initialize database schema
mysql -u ossec -p ossec < /var/ossec/src/os_dbd/mysql.schema

Log Rotation and Management

bash
# /etc/logrotate.d/ossec
/var/ossec/logs/alerts/alerts.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    postrotate
        /var/ossec/bin/ossec-control restart > /dev/null 2>&1 || true
    endscript
}

/var/ossec/logs/ossec.log {
    weekly
    missingok
    rotate 12
    compress
    delaycompress
    notifempty
    postrotate
        /var/ossec/bin/ossec-control restart > /dev/null 2>&1 || true
    endscript
}

/var/ossec/logs/active-responses.log {
    weekly
    missingok
    rotate 12
    compress
    delaycompress
    notifempty
}

Monitoring and Maintenance

Health Monitoring Script

python
#!/usr/bin/env python3
# ossec-health-monitor.py

import subprocess
import os
import time
from datetime import datetime, timedelta

class OSSECHealthMonitor:
    def __init__(self):
        self.ossec_dir = "/var/ossec"
        self.log_dir = f"{self.ossec_dir}/logs"
        self.alerts_log = f"{self.log_dir}/alerts/alerts.log"
        self.ossec_log = f"{self.log_dir}/ossec.log"
    
    def check_processes(self):
        """Check if OSSEC processes are running"""
        try:
            result = subprocess.run(['pgrep', '-f', 'ossec'], 
                                  capture_output=True, text=True)
            processes = result.stdout.strip().split('\n') if result.stdout.strip() else []
            return len(processes) > 0, f"Found {len(processes)} OSSEC processes"
        except Exception as e:
            return False, f"Error checking processes: {e}"
    
    def check_log_freshness(self):
        """Check if logs are being generated"""
        try:
            if not os.path.exists(self.alerts_log):
                return False, "Alerts log file not found"
            
            mtime = datetime.fromtimestamp(os.path.getmtime(self.alerts_log))
            if datetime.now() - mtime > timedelta(hours=1):
                return False, "Alerts log appears stale"
            
            return True, "Logs are fresh"
        except Exception as e:
            return False, f"Error checking log freshness: {e}"
    
    def check_agent_connectivity(self):
        """Check agent connectivity"""
        try:
            result = subprocess.run([f'{self.ossec_dir}/bin/agent_control', '-l'], 
                                  capture_output=True, text=True)
            
            if result.returncode != 0:
                return False, "Unable to get agent list"
            
            lines = result.stdout.strip().split('\n')
            total_agents = 0
            active_agents = 0
            
            for line in lines:
                if 'ID:' in line and 'Name:' in line:
                    total_agents += 1
                    if 'Active' in line:
                        active_agents += 1
            
            return True, f"Agents: {active_agents}/{total_agents} active"
        except Exception as e:
            return False, f"Error checking agents: {e}"
    
    def check_disk_space(self):
        """Check available disk space"""
        try:
            import shutil
            total, used, free = shutil.disk_usage(self.log_dir)
            free_percent = (free / total) * 100
            
            if free_percent < 10:
                return False, f"Low disk space: {free_percent:.1f}% free"
            
            return True, f"Disk space OK: {free_percent:.1f}% free"
        except Exception as e:
            return False, f"Error checking disk space: {e}"
    
    def get_recent_alerts(self):
        """Get count of recent alerts"""
        try:
            one_hour_ago = datetime.now() - timedelta(hours=1)
            alert_count = 0
            
            if os.path.exists(self.alerts_log):
                with open(self.alerts_log, 'r') as f:
                    for line in f:
                        if line.startswith('** Alert'):
                            # Extract timestamp (simplified)
                            try:
                                timestamp_line = next(f, '')
                                if timestamp_line.startswith('20'):
                                    # Parse OSSEC timestamp format
                                    alert_count += 1
                            except:
                                continue
            
            return alert_count
        except Exception:
            return 0
    
    def run_health_check(self):
        """Run comprehensive health check"""
        print(f"OSSEC Health Check - {datetime.now()}")
        print("=" * 50)
        
        # Process status
        proc_status, proc_message = self.check_processes()
        print(f"{'✓' if proc_status else '✗'} Processes: {proc_message}")
        
        # Log freshness
        log_status, log_message = self.check_log_freshness()
        print(f"{'✓' if log_status else '✗'} Log freshness: {log_message}")
        
        # Agent connectivity
        agent_status, agent_message = self.check_agent_connectivity()
        print(f"{'✓' if agent_status else '✗'} Agent connectivity: {agent_message}")
        
        # Disk space
        disk_status, disk_message = self.check_disk_space()
        print(f"{'✓' if disk_status else '✗'} Disk space: {disk_message}")
        
        # Recent alerts
        alert_count = self.get_recent_alerts()
        print(f"ℹ Recent alerts: {alert_count} in last hour")
        
        print()

def main():
    monitor = OSSECHealthMonitor()
    
    while True:
        try:
            monitor.run_health_check()
            time.sleep(300)  # Check every 5 minutes
        except KeyboardInterrupt:
            print("Monitoring stopped")
            break
        except Exception as e:
            print(f"Monitoring error: {e}")
            time.sleep(60)

if __name__ == "__main__":
    main()

Automated Maintenance Script

bash
#!/bin/bash
# ossec-maintenance.sh

OSSEC_DIR="/var/ossec"
LOG_DIR="$OSSEC_DIR/logs"
BACKUP_DIR="/var/backups/ossec"
RETENTION_DAYS=30

# Create backup directory
mkdir -p "$BACKUP_DIR"

# Function to backup configuration
backup_config() {
    echo "Backing up OSSEC configuration..."
    tar -czf "$BACKUP_DIR/ossec-config-$(date +%Y%m%d).tar.gz" \
        -C "$OSSEC_DIR" etc rules
    echo "Configuration backup completed"
}

# Function to clean old logs
clean_old_logs() {
    echo "Cleaning old log files..."
    find "$LOG_DIR" -name "*.log.*" -mtime +$RETENTION_DAYS -delete
    find "$LOG_DIR" -name "alerts.log.*" -mtime +$RETENTION_DAYS -delete
    echo "Old logs cleaned"
}

# Function to update rules
update_rules() {
    echo "Updating OSSEC rules..."
    
    # Backup current rules
    tar -czf "$BACKUP_DIR/rules-backup-$(date +%Y%m%d).tar.gz" \
        -C "$OSSEC_DIR" rules
    
    # Download latest rules (if using external sources)
    # wget -O /tmp/new_rules.xml https://example.com/ossec_rules.xml
    # cp /tmp/new_rules.xml "$OSSEC_DIR/rules/custom_rules.xml"
    
    # Test configuration
    if $OSSEC_DIR/bin/ossec-control test; then
        echo "Rule update successful"
        $OSSEC_DIR/bin/ossec-control restart
    else
        echo "Rule update failed - restoring backup"
        tar -xzf "$BACKUP_DIR/rules-backup-$(date +%Y%m%d).tar.gz" \
            -C "$OSSEC_DIR"
    fi
}

# Function to check agent status
check_agents() {
    echo "Checking agent status..."
    $OSSEC_DIR/bin/agent_control -l | grep -E "(Disconnected|Never connected)" | \
    while read line; do
        echo "WARNING: $line"
    done
}

# Function to generate statistics
generate_stats() {
    echo "Generating daily statistics..."
    
    STATS_FILE="$BACKUP_DIR/stats-$(date +%Y%m%d).txt"
    
    echo "OSSEC Daily Statistics - $(date)" > "$STATS_FILE"
    echo "=================================" >> "$STATS_FILE"
    
    # Alert statistics
    echo "Alert Statistics:" >> "$STATS_FILE"
    grep "$(date +%Y\ %b\ %d)" "$LOG_DIR/alerts/alerts.log" | \
    grep -o "Rule: [0-9]*" | sort | uniq -c | sort -nr | head -10 >> "$STATS_FILE"
    
    # Agent statistics
    echo -e "\nAgent Statistics:" >> "$STATS_FILE"
    $OSSEC_DIR/bin/agent_control -l >> "$STATS_FILE"
    
    echo "Statistics saved to $STATS_FILE"
}

# Main execution
case "$1" in
    backup)
        backup_config
        ;;
    clean)
        clean_old_logs
        ;;
    update)
        update_rules
        ;;
    check)
        check_agents
        ;;
    stats)
        generate_stats
        ;;
    all)
        backup_config
        clean_old_logs
        check_agents
        generate_stats
        ;;
    *)
        echo "Usage: $0 {backup|clean|update|check|stats|all}"
        echo "  backup  - Backup configuration and rules"
        echo "  clean   - Clean old log files"
        echo "  update  - Update rules"
        echo "  check   - Check agent status"
        echo "  stats   - Generate statistics"
        echo "  all     - Run all maintenance tasks"
        exit 1
        ;;
esac

Best Practices

Security Hardening

xml
<!-- Security hardening configuration -->
<ossec_config>
  <global>
    <email_notification>yes</email_notification>
    <email_maxperhour>12</email_maxperhour>
    <agents_disconnection_time>300</agents_disconnection_time>
    <agents_disconnection_alert_time>600</agents_disconnection_alert_time>
  </global>

  <alerts>
    <log_alert_level>1</log_alert_level>
    <email_alert_level>7</email_alert_level>
    <use_geoip>yes</use_geoip>
  </alerts>

  <remote>
    <connection>secure</connection>
    <port>1514</port>
    <protocol>udp</protocol>
    <allowed-ips>192.168.1.0/24</allowed-ips>
  </remote>
</ossec_config>

Performance Optimization

bash
# System-level optimizations
echo 'net.core.rmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.core.wmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.core.netdev_max_backlog = 5000' >> /etc/sysctl.conf
sysctl -p

# OSSEC process limits
echo 'ossec soft nofile 65536' >> /etc/security/limits.conf
echo 'ossec hard nofile 65536' >> /etc/security/limits.conf

Compliance Configuration

xml
<!-- PCI DSS compliance configuration -->
<ossec_config>
  <syscheck>
    <frequency>79200</frequency>
    <directories check_all="yes" realtime="yes">/etc,/usr/bin,/usr/sbin</directories>
    <directories check_all="yes" realtime="yes">/bin,/sbin</directories>
    <directories check_all="yes" realtime="yes">/var/www</directories>
  </syscheck>

  <rootcheck>
    <disabled>no</disabled>
    <check_files>yes</check_files>
    <check_trojans>yes</check_trojans>
    <check_dev>yes</check_dev>
    <check_sys>yes</check_sys>
    <check_pids>yes</check_pids>
    <check_ports>yes</check_ports>
    <check_if>yes</check_if>
    <frequency>79200</frequency>
  </rootcheck>
</ossec_config>

Troubleshooting

Common Issues

bash
# Issue: Agent not connecting
# Check agent key
sudo /var/ossec/bin/manage_agents -l

# Check network connectivity
telnet ossec-server 1514

# Check agent logs
tail -f /var/ossec/logs/ossec.log

# Issue: High false positives
# Adjust alert levels
grep "log_alert_level" /var/ossec/etc/ossec.conf

# Add white list entries
echo "192.168.1.100" >> /var/ossec/etc/ossec.conf

# Issue: Missing alerts
# Check rule configuration
/var/ossec/bin/ossec-control test

# Verify log sources
grep "localfile" /var/ossec/etc/ossec.conf

# Issue: Performance problems
# Check process status
ps aux | grep ossec

# Monitor resource usage
top -p $(pgrep ossec)

Debug Mode

bash
# Enable debug mode
/var/ossec/bin/ossec-control enable debug

# Check debug logs
tail -f /var/ossec/logs/ossec.log

# Test specific rules
/var/ossec/bin/ossec-logtest

# Analyze configuration
/var/ossec/bin/ossec-control test

Resources


This cheat sheet provides comprehensive guidance for deploying and managing OSSEC for host-based intrusion detection. Regular rule updates and proper configuration are essential for effective security monitoring.