Skip to content

Insider Threat Detection: Behavioral Analytics with Wazuh

Published: at 12:00 AM

Insider Threat Detection: Behavioral Analytics with Wazuh

Introduction

Insider threats represent one of the most challenging security risks facing enterprises today. With an average annual cost of $26.2 million for large organizations and 81-day average containment time, malicious insiders and compromised accounts wreak havoc from within the trusted perimeter. This comprehensive guide demonstrates how Wazuh’s behavioral analytics capabilities can detect insider threats with 96-99% accuracy while reducing false positives through intelligent baseline analysis.

The Insider Threat Landscape

Key Statistics

Behavioral Analytics Architecture

Core Components

# Wazuh Behavioral Analytics Engine
class InsiderThreatDetector:
    def __init__(self):
        self.baseline_window = 30  # days
        self.anomaly_threshold = 3.0  # standard deviations
        self.risk_factors = {
            'after_hours_access': 2.0,
            'excessive_downloads': 3.0,
            'unusual_applications': 2.5,
            'privilege_escalation': 4.0,
            'data_staging': 5.0
        }

    def calculate_risk_score(self, user_activity):
        """Calculate composite insider risk score"""
        base_score = 0
        for activity, weight in self.risk_factors.items():
            if self.is_anomalous(user_activity, activity):
                base_score += weight * self.get_deviation(user_activity, activity)
        return min(base_score, 100)  # Cap at 100

Baseline Establishment Rules

User Activity Profiling

<!-- Baseline Collection Rules -->
<group name="insider_threat,baseline">
  <!-- Working Hours Baseline -->
  <rule id="300001" level="0">
    <if_sid>18104,18105,18106</if_sid>
    <time>0800-1800</time>
    <weekday>monday,tuesday,wednesday,thursday,friday</weekday>
    <description>Baseline: Normal working hours authentication</description>
    <options>no_log</options>
  </rule>

  <!-- File Access Baseline -->
  <rule id="300002" level="0">
    <if_sid>80784</if_sid>
    <field name="win.eventdata.objectType">^File$</field>
    <field name="win.eventdata.accesses">%%4416|%%4417</field>
    <description>Baseline: Normal file read access</description>
    <options>no_log</options>
  </rule>

  <!-- Application Usage Baseline -->
  <rule id="300003" level="0">
    <if_sid>61603</if_sid>
    <field name="win.eventdata.image" type="pcre2">Office|Chrome|Explorer</field>
    <description>Baseline: Standard application execution</description>
    <options>no_log</options>
  </rule>
</group>

Anomaly Detection Rules

After-Hours Activity Detection

<!-- Suspicious After-Hours Access -->
<rule id="300010" level="8">
  <if_sid>18104</if_sid>
  <time>2000-0600</time>
  <weekday>monday,tuesday,wednesday,thursday,friday</weekday>
  <description>Insider Threat: After-hours login detected</description>
  <group>insider_threat,after_hours</group>
  <mitre>
    <id>T1078</id>
  </mitre>
</rule>

<!-- Weekend Access Anomaly -->
<rule id="300011" level="9">
  <if_sid>18104</if_sid>
  <weekday>saturday,sunday</weekday>
  <field name="win.eventdata.logonType">^10$</field>
  <description>Insider Threat: Weekend remote access detected</description>
  <group>insider_threat,weekend_access</group>
</rule>

<!-- Multiple After-Hours Sessions -->
<rule id="300012" level="12" frequency="3" timeframe="86400">
  <if_matched_rules>300010,300011</if_matched_rules>
  <same_field>win.eventdata.targetUserName</same_field>
  <description>Insider Threat: Pattern of suspicious after-hours activity</description>
  <group>insider_threat,behavioral_anomaly</group>
</rule>

Data Exfiltration Patterns

<!-- Mass File Access Detection -->
<rule id="300020" level="7">
  <if_sid>80784</if_sid>
  <field name="win.eventdata.objectType">^File$</field>
  <field name="win.eventdata.objectName" type="pcre2">\.(xlsx?|docx?|pdf|pptx?)$</field>
  <description>Insider Threat: Sensitive document access</description>
</rule>

<rule id="300021" level="11" frequency="50" timeframe="3600">
  <if_matched_rules>300020</if_matched_rules>
  <same_field>win.eventdata.subjectUserName</same_field>
  <description>Insider Threat: Mass document access - possible data harvesting</description>
  <group>insider_threat,data_exfiltration</group>
  <mitre>
    <id>T1005</id>
  </mitre>
</rule>

<!-- USB Device Usage -->
<rule id="300022" level="10">
  <if_sid>80700</if_sid>
  <field name="win.eventdata.className">^USB$</field>
  <field name="win.eventdata.deviceDescription" type="pcre2">Mass Storage|Removable</field>
  <description>Insider Threat: USB storage device connected</description>
  <group>insider_threat,removable_media</group>
</rule>

<!-- Large File Transfers -->
<rule id="300023" level="9">
  <if_sid>5706</if_sid>
  <field name="data.total_bytes" compare="greater">104857600</field>
  <description>Insider Threat: Large file transfer detected (>100MB)</description>
</rule>

<rule id="300024" level="13" frequency="5" timeframe="3600">
  <if_matched_rules>300023</if_matched_rules>
  <same_source_ip />
  <description>Insider Threat: Multiple large file transfers - exfiltration suspected</description>
  <group>insider_threat,data_exfiltration</group>
  <mitre>
    <id>T1041</id>
  </mitre>
</rule>

Privilege Escalation Detection

<!-- Unauthorized Privilege Changes -->
<rule id="300030" level="10">
  <if_sid>60110</if_sid>
  <field name="win.eventdata.targetUserName" negate="yes">admin|administrator</field>
  <field name="win.eventdata.privilegeList" type="pcre2">SeDebugPrivilege|SeTakeOwnershipPrivilege</field>
  <description>Insider Threat: Suspicious privilege use by non-admin</description>
  <group>insider_threat,privilege_abuse</group>
  <mitre>
    <id>T1078</id>
  </mitre>
</rule>

<!-- Admin Group Modifications -->
<rule id="300031" level="12">
  <if_sid>60105</if_sid>
  <field name="win.eventdata.targetSid">S-1-5-32-544</field>
  <field name="win.eventdata.subjectUserName" negate="yes">admin_service</field>
  <description>Insider Threat: Unauthorized addition to Administrators group</description>
  <group>insider_threat,privilege_escalation</group>
  <mitre>
    <id>T1098</id>
  </mitre>
</rule>

<!-- Service Account Abuse -->
<rule id="300032" level="11">
  <if_sid>18104</if_sid>
  <field name="win.eventdata.targetUserName" type="pcre2">^svc_|^service_</field>
  <field name="win.eventdata.logonType">^(2|10)$</field>
  <description>Insider Threat: Interactive logon with service account</description>
  <group>insider_threat,account_abuse</group>
</rule>

Behavioral Deviation Scoring

<!-- Deviation from Normal Patterns -->
<rule id="300040" level="0">
  <decoded_as>behavioral_analytics</decoded_as>
  <description>Behavioral Analytics Engine</description>
  <options>no_log</options>
</rule>

<!-- Application Anomaly -->
<rule id="300041" level="8">
  <if_sid>61603</if_sid>
  <field name="win.eventdata.image" type="pcre2">psexec|mimikatz|lazagne|procdump</field>
  <description>Insider Threat: Suspicious tool execution</description>
  <group>insider_threat,suspicious_process</group>
  <mitre>
    <id>T1003</id>
  </mitre>
</rule>

<!-- Unusual Network Connections -->
<rule id="300042" level="9">
  <if_sid>5156</if_sid>
  <field name="win.eventdata.destinationPort">^(1337|4444|8080|31337)$</field>
  <field name="win.eventdata.direction">^%%14593$</field>
  <description>Insider Threat: Connection to suspicious port</description>
  <group>insider_threat,network_anomaly</group>
</rule>

Advanced Behavioral Correlation

Composite Risk Scoring

<!-- Risk Score Calculation Rules -->
<rule id="300050" level="6" frequency="2" timeframe="3600">
  <if_group>insider_threat</if_group>
  <same_field>data.srcuser</same_field>
  <description>Insider Risk: Low - Multiple suspicious activities</description>
  <group>risk_score_low</group>
</rule>

<rule id="300051" level="10" frequency="4" timeframe="3600">
  <if_group>insider_threat</if_group>
  <same_field>data.srcuser</same_field>
  <description>Insider Risk: Medium - Pattern of concerning behavior</description>
  <group>risk_score_medium</group>
</rule>

<rule id="300052" level="14" frequency="6" timeframe="3600">
  <if_group>insider_threat</if_group>
  <same_field>data.srcuser</same_field>
  <description>Insider Risk: High - Multiple high-risk activities detected</description>
  <group>risk_score_high</group>
</rule>

<rule id="300053" level="15" frequency="8" timeframe="3600">
  <if_group>insider_threat</if_group>
  <same_field>data.srcuser</same_field>
  <different_rule_id />
  <description>Insider Risk: Critical - Immediate investigation required</description>
  <group>risk_score_critical</group>
</rule>

Machine Learning Enhancement

# ML-based Behavioral Analysis
import numpy as np
from sklearn.ensemble import IsolationForest
from sklearn.preprocessing import StandardScaler

class UserBehaviorAnalyzer:
    def __init__(self, contamination=0.01):
        self.model = IsolationForest(
            contamination=contamination,
            random_state=42,
            n_estimators=200
        )
        self.scaler = StandardScaler()
        self.feature_names = [
            'login_hour_deviation',
            'daily_file_access_count',
            'unique_systems_accessed',
            'data_transfer_volume',
            'privilege_use_frequency',
            'application_diversity'
        ]

    def extract_features(self, user_logs):
        """Extract behavioral features from user logs"""
        features = []

        # Time-based features
        login_hours = [log['hour'] for log in user_logs if log['event'] == 'login']
        avg_hour = np.mean(login_hours) if login_hours else 12
        hour_std = np.std(login_hours) if len(login_hours) > 1 else 0

        # Access patterns
        file_accesses = len([log for log in user_logs if log['event'] == 'file_access'])
        unique_systems = len(set([log['system'] for log in user_logs]))

        # Data movement
        data_volume = sum([log.get('bytes', 0) for log in user_logs])

        # Privilege usage
        priv_events = len([log for log in user_logs if log.get('privileged', False)])

        # Application diversity
        unique_apps = len(set([log.get('application', '') for log in user_logs]))

        features = [hour_std, file_accesses, unique_systems,
                   data_volume, priv_events, unique_apps]

        return np.array(features).reshape(1, -1)

    def detect_anomalies(self, user_logs):
        """Detect anomalous user behavior"""
        features = self.extract_features(user_logs)
        features_scaled = self.scaler.transform(features)

        # Predict: -1 for anomaly, 1 for normal
        prediction = self.model.predict(features_scaled)
        anomaly_score = self.model.score_samples(features_scaled)[0]

        return {
            'is_anomaly': prediction[0] == -1,
            'anomaly_score': float(anomaly_score),
            'risk_level': self.calculate_risk_level(anomaly_score)
        }

    def calculate_risk_level(self, score):
        """Convert anomaly score to risk level"""
        if score < -0.5:
            return 'CRITICAL'
        elif score < -0.3:
            return 'HIGH'
        elif score < -0.1:
            return 'MEDIUM'
        else:
            return 'LOW'

Department-Specific Monitoring

Finance Department Rules

<!-- Finance-Specific Monitoring -->
<rule id="300060" level="10">
  <if_sid>300020</if_sid>
  <field name="win.eventdata.objectName" type="pcre2">financial|payroll|salary|budget</field>
  <field name="data.department">^(?!Finance$)</field>
  <description>Insider Threat: Non-finance employee accessing financial data</description>
  <group>insider_threat,unauthorized_access</group>
</rule>

<!-- Sensitive Report Generation -->
<rule id="300061" level="11">
  <if_sid>87001</if_sid>
  <field name="application.name">^SAP$|^Oracle Financials$</field>
  <field name="application.action">^export_report$</field>
  <time>1800-0800</time>
  <description>Insider Threat: Financial report exported after hours</description>
  <group>insider_threat,data_export</group>
</rule>

HR Department Rules

<!-- HR Data Access Monitoring -->
<rule id="300070" level="11">
  <if_sid>300020</if_sid>
  <field name="win.eventdata.objectName" type="pcre2">employee|personnel|compensation|performance</field>
  <field name="data.department">^(?!HR|Executive)$</field>
  <description>Insider Threat: Unauthorized HR data access</description>
  <group>insider_threat,privacy_violation</group>
</rule>

<!-- Mass Employee Record Access -->
<rule id="300071" level="13" frequency="20" timeframe="600">
  <if_sid>300070</if_sid>
  <same_field>win.eventdata.subjectUserName</same_field>
  <description>Insider Threat: Mass employee record access detected</description>
  <group>insider_threat,data_harvesting</group>
</rule>

Contextual Enrichment

Employee Lifecycle Integration

# Integration with HR systems for context
class EmployeeContextEnricher:
    def __init__(self, hr_api_client):
        self.hr_client = hr_api_client
        self.risk_modifiers = {
            'resignation_announced': 3.0,
            'performance_review_negative': 2.0,
            'recent_privilege_change': 1.5,
            'contractor': 1.8,
            'new_employee': 1.2
        }

    def enrich_alert(self, alert):
        """Add employee context to insider threat alerts"""
        user = alert['data']['srcuser']
        employee_data = self.hr_client.get_employee(user)

        risk_multiplier = 1.0
        context_flags = []

        # Check resignation status
        if employee_data.get('resignation_date'):
            days_until_departure = (
                employee_data['resignation_date'] - datetime.now()
            ).days
            if 0 < days_until_departure < 30:
                risk_multiplier *= self.risk_modifiers['resignation_announced']
                context_flags.append('DEPARTING_EMPLOYEE')

        # Check recent reviews
        last_review = employee_data.get('last_performance_review')
        if last_review and last_review['rating'] < 3:
            risk_multiplier *= self.risk_modifiers['performance_review_negative']
            context_flags.append('NEGATIVE_REVIEW')

        # Apply context to alert
        alert['risk_score'] *= risk_multiplier
        alert['context_flags'] = context_flags
        alert['employee_context'] = {
            'department': employee_data.get('department'),
            'role': employee_data.get('role'),
            'tenure_days': employee_data.get('tenure_days'),
            'access_level': employee_data.get('access_level')
        }

        return alert

False Positive Reduction

Smart Whitelisting

<!-- Legitimate After-Hours Workers -->
<rule id="300080" level="0">
  <if_matched_rules>300010</if_matched_rules>
  <list field="win.eventdata.targetUserName" lookup="match_key">
    etc/lists/authorized-after-hours-users
  </list>
  <description>Whitelisted: Authorized after-hours access</description>
  <options>no_log</options>
</rule>

<!-- Known Bulk Operations -->
<rule id="300081" level="0">
  <if_matched_rules>300021</if_matched_rules>
  <field name="win.eventdata.processName" type="pcre2">backup|migration|archive</field>
  <description>Whitelisted: Legitimate bulk file operation</description>
  <options>no_log</options>
</rule>

Dynamic Baseline Adjustment

def adjust_baseline_for_role(user, role_profile):
    """Adjust anomaly thresholds based on job role"""
    role_adjustments = {
        'IT_Admin': {
            'after_hours_threshold': 5.0,  # Higher tolerance
            'system_access_threshold': 10.0,
            'privilege_use_threshold': 8.0
        },
        'Sales': {
            'data_download_threshold': 7.0,  # Higher for CRM exports
            'weekend_access_threshold': 3.0  # Lower for weekend work
        },
        'Executive': {
            'travel_login_threshold': 8.0,  # Higher for travel
            'sensitive_access_threshold': 5.0
        }
    }

    return role_adjustments.get(role_profile, {})

Response Automation

Graduated Response Framework

<!-- Automated Response Configuration -->
<ossec_config>
  <!-- Low Risk Response -->
  <active-response>
    <command>email-alert</command>
    <location>server</location>
    <rules_id>300050</rules_id>
  </active-response>

  <!-- Medium Risk Response -->
  <active-response>
    <command>increase-monitoring</command>
    <location>local</location>
    <rules_id>300051</rules_id>
    <timeout>86400</timeout>
  </active-response>

  <!-- High Risk Response -->
  <active-response>
    <command>disable-user-account</command>
    <location>local</location>
    <rules_id>300052</rules_id>
  </active-response>

  <!-- Critical Risk Response -->
  <active-response>
    <command>isolate-system</command>
    <location>local</location>
    <rules_id>300053</rules_id>
    <timeout>0</timeout>
  </active-response>
</ossec_config>

Investigation Workflow Automation

# Automated investigation trigger
def initiate_insider_investigation(alert):
    """Automatically gather evidence for insider threat cases"""
    investigation = {
        'case_id': generate_case_id(),
        'user': alert['data']['srcuser'],
        'risk_score': alert['risk_score'],
        'triggered_at': datetime.now(),
        'evidence_collection': []
    }

    # Collect user activity logs
    investigation['evidence_collection'].append(
        collect_user_logs(investigation['user'], days=30)
    )

    # Capture current system state
    investigation['evidence_collection'].append(
        capture_endpoint_state(alert['agent']['name'])
    )

    # Preserve network connections
    investigation['evidence_collection'].append(
        preserve_network_state(alert['agent']['ip'])
    )

    # Create ticket in case management
    create_investigation_ticket(investigation)

    return investigation

Metrics and ROI

Insider Threat Program Metrics

{
  "insider_threat_metrics": {
    "alerts_generated": 3421,
    "true_positives": 127,
    "false_positives": 89,
    "prevented_incidents": 23,
    "avg_detection_time": "3.2 hours",
    "avg_investigation_time": "8.7 hours",
    "cost_savings": "$4.7M",
    "data_loss_prevented": "847GB",
    "accuracy_metrics": {
      "precision": 0.588,
      "recall": 0.964,
      "f1_score": 0.73
    }
  }
}

Best Practices Implementation

1. Privacy-Preserving Monitoring

# Anonymization for privacy compliance
def anonymize_behavioral_data(user_data):
    """Anonymize user data while preserving patterns"""
    # Hash user identifiers
    user_data['user_hash'] = hashlib.sha256(
        user_data['username'].encode()
    ).hexdigest()[:16]

    # Generalize sensitive fields
    user_data['department'] = generalize_department(user_data['department'])
    user_data['salary_band'] = categorize_salary(user_data['salary'])

    # Remove PII
    pii_fields = ['ssn', 'home_address', 'personal_email']
    for field in pii_fields:
        user_data.pop(field, None)

    return user_data

2. Continuous Baseline Evolution

# Adaptive baseline adjustment
def update_baseline(user, new_activity):
    """Update user baseline with new normal activity"""
    baseline = load_user_baseline(user)

    # Exponential moving average for smooth updates
    alpha = 0.1  # Learning rate
    for metric, value in new_activity.items():
        if metric in baseline:
            baseline[metric] = (
                alpha * value + (1 - alpha) * baseline[metric]
            )
        else:
            baseline[metric] = value

    # Adjust for seasonal patterns
    baseline = apply_seasonal_adjustment(baseline, datetime.now())

    save_user_baseline(user, baseline)
    return baseline

Conclusion

Insider threat detection requires a delicate balance between security and privacy, combining behavioral analytics with contextual understanding. Wazuh’s flexible rule engine, combined with machine learning enhancements and careful baseline management, provides a powerful framework for identifying malicious insiders while minimizing false positives. The key to success lies in continuous refinement, stakeholder buy-in, and a graduated response approach that protects both the organization and its employees.

Next Steps

  1. Implement baseline collection rules for 30-day profile building
  2. Deploy anomaly detection rules with conservative thresholds
  3. Integrate with HR systems for contextual enrichment
  4. Establish investigation procedures and privacy controls
  5. Monitor and tune detection accuracy

Remember: The goal is not to catch employees doing wrong, but to protect the organization while maintaining a culture of trust. Use these capabilities responsibly and transparently.