Appearance
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
- OSSEC Official Documentation
- OSSEC GitHub Repository
- OSSEC Rules Database
- OSSEC Community
- Wazuh (OSSEC Fork)
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.