// Overview

Built to emulate enterprise environments, the ascendant.design SOC Homelab is a fully virtualized cybersecurity training ground for hands-on threat detection. Hosted on VirtualBox within a securely isolated network, the architecture consists of five virtual machines: a Windows Server 2022 Domain Controller, a Windows 10 Pro endpoint, a vulnerable Metasploitable 2 instance, and a Kali Linux attack node. Centralized monitoring is handled by a Wazuh SIEM, which actively detects simulated malicious behavior and correlates it directly with the MITRE ATT&CK framework.

// Overview

Built to emulate enterprise environments, the ascendant.design SOC Homelab is a fully virtualized cybersecurity training ground for hands-on threat detection. Hosted on VirtualBox within a securely isolated network, the architecture consists of five virtual machines: a Windows Server 2022 Domain Controller, a Windows 10 Pro endpoint, a vulnerable Metasploitable 2 instance, and a Kali Linux attack node. Centralized monitoring is handled by a Wazuh SIEM, which actively detects simulated malicious behavior and correlates it directly with the MITRE ATT&CK framework.

// SOC Live Dashboard

This live dashboard provides a real-time window into the automated telemetry captured across your virtualized cybersecurity infrastructure. It aggregates threat intelligence from active Wazuh SIEM endpoints—tracking total event volume, classifying alerts by risk severity level, and mapping incoming security events directly to the MITRE ATT&CK framework. Designed to showcase automated endpoint protection and continuous threat monitoring, the feed highlights active attack vectors and system telemetry in real time.

Architecture Overview: Decoupled Telemetry Pipeline

This dashboard relies on a decoupled, push-based telemetry pipeline to securely bridge an isolated SIEM with a public web environment. An autonomous Python script on the Wazuh server queries the local OpenSearch API for security metrics—such as MITRE ATT&CK mappings and alert severities—and pushes them outbound as a lightweight JSON payload. Utilizing a pre-shared key (PSK) and custom headers, this outbound-only transmission bypasses external firewalls and maintains strict network segmentation, completely hiding the internal SIEM from inbound internet traffic.

Upon receipt, a custom WordPress REST API endpoint validates the payload and caches it in memory using Transients. This stateless caching prevents database thrashing and guarantees instantaneous page loads. Custom shortcodes then dynamically render the cached intelligence into responsive dashboards, delivering real-time SOC visibility with zero direct infrastructure exposure.

Event Volume (Last 24 Hours – UTC)

Live SOC Telemetry 3,588 Events

Severities
  • Level 31,369
  • Level 51,012
  • Level 71,005
  • Level 4127
  • Level 1031
Top MITRE Tactics
  • Defense Evasion 482
  • Privilege Escalation 272
  • Persistence 242
Active Agents
  • WIN-QK6A1G7ET00 1,477
  • HomelabWindowsP 1,318
  • Homelab-Windows 564
Top Security Events
  • Name resolution for the name settings-win.data.microsoft.com timed out 367
  • Software protection service scheduled successfully. 237
  • Windows User Logoff 190
  • Windows Logon Success 186

Security Framework & Auth Groupings

NIST Control Hits
  • Control CM.1 1,363
  • Control AU.14 524
  • Control AU.6 314
Top Event Categories
  • Windows 1,724
  • Sca 1,362
  • Windows_system 626
  • Windows_security 548

Telemetry Sources

Event Channels
  • EventChannel 1,724
  • sca 1,363
  • syscheck 282
  • journald 60
  • /var/log/audit/audit.log 50

SOC Live Dashboard

This live dashboard provides a real-time window into the automated telemetry captured across your virtualized cybersecurity infrastructure. It aggregates threat intelligence from active Wazuh SIEM endpoints—tracking total event volume, classifying alerts by risk severity level, and mapping incoming security events directly to the MITRE ATT&CK framework. Designed to showcase automated endpoint protection and continuous threat monitoring, the feed highlights active attack vectors and system telemetry in real time.

Architecture Overview: Decoupled Telemetry Pipeline

This dashboard relies on a decoupled, push-based telemetry pipeline to securely bridge an isolated SIEM with a public web environment. An autonomous Python script on the Wazuh server queries the local OpenSearch API for security metrics—such as MITRE ATT&CK mappings and alert severities—and pushes them outbound as a lightweight JSON payload. Utilizing a pre-shared key (PSK) and custom headers, this outbound-only transmission bypasses external firewalls and maintains strict network segmentation, completely hiding the internal SIEM from inbound internet traffic.

Upon receipt, a custom WordPress REST API endpoint validates the payload and caches it in memory using Transients. This stateless caching prevents database thrashing and guarantees instantaneous page loads. Custom shortcodes then dynamically render the cached intelligence into responsive dashboards, delivering real-time SOC visibility with zero direct infrastructure exposure.

Event Volume (Last 24 Hours – UTC)

Live SOC Telemetry 3,588 Events

Severities
  • Level 31,369
  • Level 51,012
  • Level 71,005
  • Level 4127
  • Level 1031
Top MITRE Tactics
  • Defense Evasion 482
  • Privilege Escalation 272
  • Persistence 242
Active Agents
  • WIN-QK6A1G7ET00 1,477
  • HomelabWindowsP 1,318
  • Homelab-Windows 564
Top Security Events
  • Name resolution for the name settings-win.data.microsoft.com timed out 367
  • Software protection service scheduled successfully. 237
  • Windows User Logoff 190
  • Windows Logon Success 186

Security Framework & Auth Groupings

NIST Control Hits
  • Control CM.1 1,363
  • Control AU.14 524
  • Control AU.6 314
Top Event Categories
  • Windows 1,724
  • Sca 1,362
  • Windows_system 626
  • Windows_security 548

Telemetry Sources

Event Channels
  • EventChannel 1,724
  • sca 1,363
  • syscheck 282
  • journald 60
  • /var/log/audit/audit.log 50

// Tech Stack

Wazuh SIEM Manager
Kali Linux Virtual Machine
Windows 2022 Active Dir
Ubuntu Linux Instance
Windows 11 Pro Instance
Windows 11 Home Instance

// Network Overview

VM ROLE OS IP
DC1 Domain Controller Windows 2022 Server 192.168.128.6
Wazuh SIEM SIEM Ubuntu 22.04 192.168.128.8
Client1 Workstation Windows 11 Pro 192.168.128.7
Client2 Workstation Windows 11 Home 192.168.128.4
Client3 Workstation Ubuntu 22.04 192.168.128.5
Kali Linux Attacker Attacker Kali Linux 192.168.128.9

// Wazuh SIEM PHP Construction Script

				
					<?php
// --- 1. DATA CATCHER ---
add_action('rest_api_init', function () {
    register_rest_route('soc/v1', '/telemetry', array(
        'methods' => 'POST',
        'callback' => 'update_wazuh_telemetry',
        'permission_callback' => '__return_true'
    ));
});

function update_wazuh_telemetry($request) {
    $secret_token = 'INSERT_YOUR_SECRET_HERE'; 
    if ($request->get_header('x-api-key') !== $secret_token) {
        return new WP_Error('unauthorized', 'Invalid Token', array('status' => 401));
    }
    set_transient('wazuh_alert_stats_cache', $request->get_json_params(), 600); 
    return rest_ensure_response(array('status' => 'success'));
}

function get_wz_color($index) {
    $colors = array('#ef4444', '#f97316', '#facc15', '#22c55e', '#009fe3');
    return $colors[$index % count($colors)];
}

// --- 2. WIDGET 1: MASTER DASHBOARD ---
function display_wazuh_telemetry() {
    $data = get_transient('wazuh_alert_stats_cache');
    if (empty($data) || !isset($data['severities'])) return '<p>Awaiting Data...</p>';
    
    $html = '<div class="wazuh-stats-widget">';
    $html .= '<h4>Live SOC Telemetry <span class="wazuh-total-badge">' . number_format($data['total']) . ' Events</span></h4>';
    $html .= '<div class="wz-master-layout">';
    
    $html .= '<div class="wz-sidebar-severities"><h5 class="wz-section-title">Severities</h5><ul class="wz-severities-stack">';
    foreach ($data['severities'] as $sev) {
        $lvl = intval($sev['level']);
        $class = ($lvl >= 12) ? 'wz-critical' : (($lvl >= 8) ? 'wz-high' : (($lvl >= 4) ? 'wz-medium' : 'wz-low'));
        $html .= '<li class="' . $class . '"><span>Level ' . $lvl . '</span><span class="wz-count">' . number_format($sev['count']) . '</span></li>';
    }
    $html .= '</ul></div>';

    $html .= '<div class="wz-main-grid"><div class="wz-sub-row">';
    
    $html .= '<div class="wz-card"><h5 class="wz-section-title">Top MITRE Tactics</h5><ul class="wz-text-list">';
    $mitre_data = isset($data['mitre']) ? $data['mitre'] : [];
    if (empty($mitre_data)) { $html .= '<li><span>No MITRE data</span> <span>0</span></li>'; } 
    else { $i = 0; foreach ($mitre_data as $m) { $c = get_wz_color($i++); $html .= '<li style="border-bottom-color: '.$c.';"><span>' . esc_html(ucfirst($m['tactic'])) . '</span> <span style="color: '.$c.' !important;">' . number_format($m['count']) . '</span></li>'; } }
    $html .= '</ul></div>';

    $html .= '<div class="wz-card"><h5 class="wz-section-title">Active Agents</h5><ul class="wz-text-list">';
    $agent_data = isset($data['agents']) ? $data['agents'] : [];
    if (empty($agent_data)) { $html .= '<li><span>No agent data</span> <span>0</span></li>'; } 
    else { $i = 0; foreach ($agent_data as $a) { $c = get_wz_color($i++); $html .= '<li style="border-bottom-color: '.$c.';"><span>' . esc_html($a['name']) . '</span> <span style="color: '.$c.' !important;">' . number_format($a['count']) . '</span></li>'; } }
    $html .= '</ul></div></div>'; 

    $html .= '<div class="wz-card wz-full-card"><h5 class="wz-section-title">Top Security Events</h5><ul class="wz-text-list">';
    $event_data = isset($data['events']) ? $data['events'] : [];
    if (empty($event_data)) { $html .= '<li><span>No events</span> <span>0</span></li>'; } 
    else { $i = 0; foreach ($event_data as $e) { $c = get_wz_color($i++); $html .= '<li style="border-bottom-color: '.$c.';"><span>' . esc_html($e['desc']) . '</span> <span style="color: '.$c.' !important;">' . number_format($e['count']) . '</span></li>'; } }
    $html .= '</ul></div>';
    
    $html .= '</div></div></div>'; 
    return $html;
}
add_shortcode('wazuh_live_stats', 'display_wazuh_telemetry');

// --- 3. WIDGET 2: COMPLIANCE & AUTHENTICATION ---
function display_wazuh_compliance() {
    $data = get_transient('wazuh_alert_stats_cache');
    if (empty($data)) return '<p>Awaiting Data...</p>';

    $html = '<div class="wazuh-stats-widget"><h4 style="border-bottom:none; margin-bottom:10px;">Security Framework & Auth Groupings</h4>';
    $html .= '<div class="wz-sub-row">';
    
    $html .= '<div class="wz-card"><h5 class="wz-section-title">NIST Control Hits</h5><ul class="wz-text-list">';
    $nist_data = isset($data['nist']) ? $data['nist'] : [];
    if (empty($nist_data)) { $html .= '<li><span>No NIST data</span> <span>0</span></li>'; } 
    else { $i = 0; foreach ($nist_data as $n) { $c = get_wz_color($i++); $html .= '<li style="border-bottom-color: '.$c.';"><span>Control ' . esc_html($n['control']) . '</span> <span style="color: '.$c.' !important;">' . number_format($n['count']) . '</span></li>'; } }
    $html .= '</ul></div>';
    
    $html .= '<div class="wz-card"><h5 class="wz-section-title">Top Event Categories</h5><ul class="wz-text-list">';
    $group_data = isset($data['groups']) ? $data['groups'] : [];
    if (empty($group_data)) { $html .= '<li><span>No category data</span> <span>0</span></li>'; } 
    else { $i = 0; foreach ($group_data as $g) { $c = get_wz_color($i++); $html .= '<li style="border-bottom-color: '.$c.';"><span>' . esc_html(ucfirst($g['group'])) . '</span> <span style="color: '.$c.' !important;">' . number_format($g['count']) . '</span></li>'; } }
    $html .= '</ul></div></div></div>';
    return $html;
}
add_shortcode('wazuh_compliance_stats', 'display_wazuh_compliance');

// --- 4. WIDGET 3: TELEMETRY SOURCES ---
function display_wazuh_sources() {
    $data = get_transient('wazuh_alert_stats_cache');
    if (empty($data)) return '<p>Awaiting Data...</p>';

    $html = '<div class="wazuh-stats-widget"><h4>Telemetry Sources</h4>';
    $html .= '<div class="wz-card"><h5 class="wz-section-title">Event Channels</h5><ul class="wz-text-list">';
    
    $loc_data = isset($data['locations']) ? $data['locations'] : [];
    if (empty($loc_data)) { $html .= '<li><span>No source data</span> <span>0</span></li>'; } 
    else { $i = 0; foreach ($loc_data as $l) { $c = get_wz_color($i++); $loc_name = (strlen($l['loc']) > 30) ? substr($l['loc'], 0, 30) . '...' : $l['loc']; $html .= '<li style="border-bottom-color: '.$c.';"><span>' . esc_html($loc_name) . '</span> <span style="color: '.$c.' !important;">' . number_format($l['count']) . '</span></li>'; } }
    $html .= '</ul></div></div>';
    return $html;
}
add_shortcode('wazuh_source_stats', 'display_wazuh_sources');

// --- 5. WIDGET 4: TIMELINE GRAPH ---
function display_wazuh_graph() {
    $data = get_transient('wazuh_alert_stats_cache');
    if (empty($data) || !isset($data['timeline'])) return '<p>Awaiting Graph Data...</p>';

    $labels = [];
    $counts = [];
    
    foreach ((array)$data['timeline'] as $t) {
        $labels[] = gmdate('g A', intval($t['time'] / 1000));
        $counts[] = intval($t['count']);
    }

    $chart_id = 'wazuhChart_' . uniqid();

    $html = '<div class="wazuh-stats-widget">';
    $html .= '<h4 style="border-bottom:none; margin-bottom:10px;">Event Volume (Last 24 Hours - UTC)</h4>';
    $html .= '<div style="position: relative; height: 250px; width: 100%; display: block;">';
    $html .= '<canvas id="' . $chart_id . '" style="max-width: 100%; cursor: pointer;"></canvas>';
    $html .= '</div></div>';
    
    static $chart_js_loaded = false;
    if (!$chart_js_loaded) {
        $html .= '<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>';
        $chart_js_loaded = true;
    }
    
    $html .= '<script>
        (function() {
            function renderWazuhChart() {
                if (typeof Chart === "undefined") {
                    setTimeout(renderWazuhChart, 150);
                    return;
                }
                
                var canvas = document.getElementById("' . $chart_id . '");
                if (!canvas) return;
                
                var ctx = canvas.getContext("2d");
                var gradient = ctx.createLinearGradient(0, 0, 0, 300);
                gradient.addColorStop(0, "rgba(0, 159, 227, 0.4)");
                gradient.addColorStop(1, "rgba(0, 159, 227, 0.0)");
                
                var wazuhChart = new Chart(ctx, {
                    type: "line",
                    data: {
                        labels: ' . json_encode($labels) . ',
                        datasets: [{
                            label: "Security Events",
                            data: ' . json_encode($counts) . ',
                            borderColor: "#009fe3",
                            backgroundColor: gradient,
                            borderWidth: 3,
                            pointBackgroundColor: "#ffffff",
                            pointBorderColor: "#009fe3",
                            pointBorderWidth: 2,
                            pointRadius: 4,
                            pointHoverRadius: 6,
                            fill: true,
                            tension: 0.4
                        }]
                    },
                    options: {
                        responsive: true,
                        maintainAspectRatio: false,
                        plugins: { legend: { display: false } },
                        scales: {
                            x: { grid: { display: false }, ticks: { maxRotation: 45, minRotation: 45 } },
                            y: { beginAtZero: true, grid: { color: "#e5e7eb" } }
                        },
                        onClick: (e, elements) => {
                            if (elements.length > 0) {
                                const dataIndex = elements[0].index;
                                const clickedTime = wazuhChart.data.labels[dataIndex];
                                const clickedCount = wazuhChart.data.datasets[0].data[dataIndex];
                                const drillDownUrl = "/soc-investigation/?time=" + encodeURIComponent(clickedTime) + "&events=" + clickedCount;
                                window.location.href = drillDownUrl;
                            }
                        }
                    }
                });
            }
            
            if (document.readyState === "loading") {
                document.addEventListener("DOMContentLoaded", renderWazuhChart);
            } else {
                setTimeout(renderWazuhChart, 200); 
            }
        })();
    </script>';

    return $html;
}
add_shortcode('wazuh_graph_stats', 'display_wazuh_graph');

// --- 6. WIDGET 5: INCIDENT RESPONSE DRILL-DOWN MOCKUP ---
function display_wazuh_investigation() {
    $time = isset($_GET['time']) ? sanitize_text_field($_GET['time']) : 'Selected Hour';
    $events = isset($_GET['events']) ? intval($_GET['events']) : 'Multiple';

    $html = '<div class="wazuh-stats-widget">';
    $html .= '<h4>SOC Investigation Drill-Down <span class="wazuh-total-badge">' . esc_html($events) . ' Events at ' . esc_html($time) . '</span></h4>';
    $html .= '<p style="font-size: 0.85rem; color: #6b7280; margin-bottom: 20px; line-height: 1.5;"><strong>Architecture Notice:</strong> For security and performance, this portfolio environment does not expose raw internal SIEM logs to the public internet. Below is a sanitized, representative sample of the telemetry captured during this time window.</p>';

    $mock_logs = [
        ['time' => '14:02:11 UTC', 'agent' => 'WIN-QK6A1G7ET00', 'level' => 3, 'desc' => 'Windows Logon Success', 'mitre' => 'Initial Access'],
        ['time' => '14:15:43 UTC', 'agent' => 'Homelab-Windows', 'level' => 7, 'desc' => 'File added to the system', 'mitre' => 'Persistence'],
        ['time' => '14:22:09 UTC', 'agent' => 'HomelabWindowsP', 'level' => 8, 'desc' => 'Name resolution for the name settings-win.data... timed out', 'mitre' => 'Defense Evasion'],
        ['time' => '14:38:12 UTC', 'agent' => 'WIN-QK6A1G7ET00', 'level' => 12, 'desc' => 'High amount of POST requests in a small period of time', 'mitre' => 'Command and Control'],
        ['time' => '14:41:55 UTC', 'agent' => 'WIN-QK6A1G7ET00', 'level' => 5, 'desc' => 'Windows User Logoff', 'mitre' => 'None']
    ];

    $html .= '<div style="overflow-x: auto;">';
    $html .= '<table style="width: 100%; min-width: 600px; border-collapse: collapse; text-align: left; font-size: 0.8rem;">';
    $html .= '<thead><tr style="border-bottom: 2px solid #e5e7eb; color: #6b7280; text-transform: uppercase;">';
    $html .= '<th style="padding: 10px;">Timestamp</th><th style="padding: 10px;">Agent</th><th style="padding: 10px;">Level</th><th style="padding: 10px;">Description</th><th style="padding: 10px;">MITRE Tactic</th>';
    $html .= '</tr></thead><tbody>';

    foreach ($mock_logs as $log) {
        $lvl = $log['level'];
        $bg_color = ($lvl >= 12) ? '#ef4444' : (($lvl >= 8) ? '#f97316' : (($lvl >= 4) ? '#facc15' : '#009fe3'));
        $text_color = ($lvl >= 12 || $lvl < 4 || $lvl >= 8) ? '#ffffff' : '#1a1a1a';

        $html .= '<tr style="border-bottom: 1px solid #f3f4f6;">';
        $html .= '<td style="padding: 12px 10px; color: #4b5563;">' . $log['time'] . '</td>';
        $html .= '<td style="padding: 12px 10px; font-weight: 600;">' . $log['agent'] . '</td>';
        $html .= '<td style="padding: 12px 10px;"><span style="background: ' . $bg_color . '; color: ' . $text_color . '; padding: 3px 8px; border-radius: 6px; font-weight: 700;">L' . $lvl . '</span></td>';
        $html .= '<td style="padding: 12px 10px;">' . $log['desc'] . '</td>';
        $html .= '<td style="padding: 12px 10px; color: #009fe3; font-weight: 500;">' . $log['mitre'] . '</td>';
        $html .= '</tr>';
    }

    $html .= '</tbody></table></div>';
    
    $html .= '<div style="margin-top: 20px; text-align: right;">';
    $html .= '<a href="javascript:history.back()" style="display: inline-block; background: #1a1a1a; color: #ffffff; padding: 8px 16px; border-radius: 8px; text-decoration: none; font-size: 0.8rem; font-weight: 700; transition: opacity 0.2s;">&larr; Back to Dashboard</a>';
    $html .= '</div></div>';

    return $html;
}
add_shortcode('wazuh_investigation_demo', 'display_wazuh_investigation');

// --- 7. UNIVERSAL CSS ---
add_action('wp_footer', function() {
    echo '<style>
    .wazuh-stats-widget, .wazuh-stats-widget * { box-sizing: border-box !important; }
    
    .wazuh-stats-widget { background: #ffffff; border-radius: 16px; padding: 24px; width: 100%; max-width: 100%; box-shadow: 0 4px 24px rgba(0,0,0,0.04); font-family: "Inter", sans-serif; color: #1a1a1a; margin-bottom: 20px;}
    .wazuh-stats-widget h4 { margin: 0 0 20px 0; font-size: 1.1rem; font-weight: 800; letter-spacing: 0.02em; text-transform: uppercase; color: #1a1a1a !important; display: flex; align-items: center; justify-content: space-between; border-bottom: 2px solid #f3f4f6; padding-bottom: 12px; }
    .wazuh-stats-widget h4::before { content: ""; display: inline-block; width: 10px; height: 10px; background-color: #009fe3; border-radius: 50%; margin-right: 10px; box-shadow: 0 0 8px rgba(0, 159, 227, 0.6); animation: wazuh-pulse 2s infinite; }
    .wazuh-total-badge { font-size: 0.75rem; background: #e5e7eb; padding: 4px 10px; border-radius: 20px; color: #4b5563; font-weight: 700; margin-left: auto; }
    @keyframes wazuh-pulse { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; } }
    .wz-section-title { margin: 0 0 10px 0; font-size: 0.75rem; color: #6b7280; text-transform: uppercase; font-weight: 700; letter-spacing: 0.05em; }
    
    .wz-master-layout { display: flex; gap: 20px; align-items: flex-start; max-width: 100%; }
    .wz-sidebar-severities { width: 240px; flex-shrink: 0; background: #f4f5f7; padding: 14px; border-radius: 12px; }
    .wazuh-stats-widget ul.wz-severities-stack { display: flex !important; flex-direction: column !important; gap: 8px !important; list-style: none !important; padding: 0 !important; margin: 0 !important; }
    .wz-severities-stack li { display: flex !important; justify-content: space-between !important; align-items: center !important; padding: 10px 12px !important; background: #ffffff !important; border-radius: 8px !important; font-size: 0.8rem !important; font-weight: 600 !important; border-left: 4px solid #e5e7eb !important; color: #1a1a1a !important; }
    .wz-severities-stack li.wz-critical { border-left-color: #ef4444 !important; } .wz-severities-stack li.wz-high { border-left-color: #f97316 !important; } .wz-severities-stack li.wz-medium { border-left-color: #facc15 !important; } .wz-severities-stack li.wz-low { border-left-color: #009fe3 !important; }
    .wz-severities-stack .wz-count { background-color: #1a1a1a; color: #ffffff; padding: 2px 8px; border-radius: 6px; font-weight: 700; font-size: 0.85rem; width: 45px; text-align: center; }
    
    .wz-main-grid { flex: 1; display: flex; flex-direction: column; gap: 16px; min-width: 0; max-width: 100%; }
    .wz-sub-row { display: flex; gap: 16px; width: 100%; max-width: 100%; }
    .wz-card { flex: 1; background: #f4f5f7; padding: 14px; border-radius: 12px; min-width: 0; max-width: 100%; }
    .wz-full-card { width: 100%; max-width: 100%; }
    
    .wazuh-stats-widget ul.wz-text-list { display: flex !important; flex-direction: column !important; gap: 0 !important; list-style: none !important; padding: 0 !important; margin: 0 !important; width: 100%; }
    .wz-text-list li { display: flex !important; flex-direction: row !important; justify-content: space-between !important; align-items: center !important; font-size: 0.8rem !important; font-weight: 500 !important; padding: 10px 0 !important; border-bottom: 2px solid #e5e7eb !important; background: transparent !important; color: #1a1a1a !important; width: 100%; }
    .wz-text-list li:last-child { border-bottom: none !important; padding-bottom: 0 !important; }
    
    .wz-text-list li > span:first-child { flex: 1; padding-right: 12px; text-align: left; word-break: break-word; overflow-wrap: break-word; white-space: normal; }
    .wz-text-list li > span:last-child { font-weight: 700 !important; background: #ffffff !important; padding: 4px 0 !important; border-radius: 10px !important; font-size: 0.75rem !important; flex-shrink: 0 !important; width: 60px !important; text-align: center !important; display: inline-block !important; margin-left: auto !important; }
    
    @media (max-width: 768px) {
        .wazuh-stats-widget { padding: 16px; }
        .wz-master-layout { flex-direction: column; }
        .wz-sidebar-severities { width: 100%; margin-bottom: 10px; }
        .wz-main-grid { width: 100%; }
        .wz-sub-row { flex-direction: column; gap: 16px; width: 100%; }
        .wazuh-stats-widget h4 { flex-direction: column; align-items: flex-start; gap: 12px; }
        .wazuh-total-badge { margin-left: 0; }
    }
    </style>';
});
?>
				
			

// Wazuh SIEM Python Push Script

				
					import urllib.request
import json
import ssl
import base64

# --- 1. CONFIGURATION ---
WAZUH_URL = "https://INSERT_YOUR_WAZUH_IP:9200/wazuh-alerts*/_search"
WAZUH_USER = "INSERT_WAZUH_USERNAME"
WAZUH_PASS = "INSERT_WAZUH_PASSWORD"
WP_URL = "https://INSERT_YOUR_DOMAIN.com/wp-json/soc/v1/telemetry"
WP_SECRET = "INSERT_YOUR_SECRET_HERE"

ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

# --- 2. EXPANDED TIME-SERIES QUERY ---
query_body = json.dumps({
    "size": 0,
    "aggs": {
        "top_severities": { "terms": { "field": "rule.level", "size": 5 } },
        "top_agents": { "terms": { "field": "agent.name", "size": 3 } },
        "top_mitre": { "terms": { "field": "rule.mitre.tactic", "size": 3 } },
        "top_events": { "terms": { "field": "rule.description", "size": 4 } },
        "top_nist": { "terms": { "field": "rule.nist_800_53", "size": 3 } },
        "top_groups": { "terms": { "field": "rule.groups", "size": 4 } },
        "top_locations": { "terms": { "field": "location", "size": 5 } },
        "timeline": {
            "filter": { "range": { "@timestamp": { "gte": "now-24h" } } },
            "aggs": {
                "hourly": {
                    "date_histogram": {
                        "field": "@timestamp",
                        "fixed_interval": "1h",
                        "min_doc_count": 0
                    }
                }
            }
        }
    }
}).encode('utf-8')

auth_string = f"{WAZUH_USER}:{WAZUH_PASS}"
base64_auth = base64.b64encode(auth_string.encode('utf-8')).decode('utf-8')
req_local = urllib.request.Request(WAZUH_URL, data=query_body, method="POST")
req_local.add_header("Authorization", f"Basic {base64_auth}")
req_local.add_header("Content-Type", "application/json")

try:
    with urllib.request.urlopen(req_local, context=ctx) as response:
        data = json.loads(response.read().decode())
except Exception as e:
    print(f"Failed to query Wazuh: {e}")
    exit(1)

# --- 3. FORMAT THE MULTI-PART PAYLOAD ---
aggs = data.get('aggregations', {})
timeline_buckets = aggs.get('timeline', {}).get('hourly', {}).get('buckets', [])

payload = {
    "total": data.get('hits', {}).get('total', {}).get('value', 0),
    "severities": [{"level": b['key'], "count": b['doc_count']} for b in aggs.get('top_severities', {}).get('buckets', [])],
    "agents": [{"name": b['key'], "count": b['doc_count']} for b in aggs.get('top_agents', {}).get('buckets', [])],
    "mitre": [{"tactic": b['key'], "count": b['doc_count']} for b in aggs.get('top_mitre', {}).get('buckets', [])],
    "events": [{"desc": b['key'], "count": b['doc_count']} for b in aggs.get('top_events', {}).get('buckets', [])],
    "nist": [{"control": b['key'], "count": b['doc_count']} for b in aggs.get('top_nist', {}).get('buckets', [])],
    "groups": [{"group": b['key'], "count": b['doc_count']} for b in aggs.get('top_groups', {}).get('buckets', [])],
    "locations": [{"loc": b['key'], "count": b['doc_count']} for b in aggs.get('top_locations', {}).get('buckets', [])],
    "timeline": [{"time": b['key'], "count": b['doc_count']} for b in timeline_buckets[-24:]]
}

# --- 4. PUSH TO WORDPRESS ---
req_remote = urllib.request.Request(WP_URL, data=json.dumps(payload).encode('utf-8'), method="POST")
req_remote.add_header("x-api-key", WP_SECRET)
req_remote.add_header("Content-Type", "application/json")
req_remote.add_header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")

try:
    with urllib.request.urlopen(req_remote) as response:
        print(f"Successfully pushed expanded data. Status: {response.status}")
except Exception as e:
    print(f"Failed to push to WordPress: {e}")
				
			

// Wazuh Code Formatting

				
					/* Force strict boundary boxing on all widget elements */
.wazuh-stats-widget, .wazuh-stats-widget * { 
    box-sizing: border-box !important; 
}

/* Master Widget Container */
.wazuh-stats-widget { 
    background: #ffffff; 
    border-radius: 16px; 
    padding: 24px; 
    width: 100%; 
    max-width: 100%; 
    box-shadow: 0 4px 24px rgba(0,0,0,0.04); 
    font-family: "Inter", sans-serif; 
    color: #1a1a1a; 
    margin-bottom: 20px;
}

/* Header Styling & Pulsing Blue Dot */
.wazuh-stats-widget h4 { 
    margin: 0 0 20px 0; 
    font-size: 1.1rem; 
    font-weight: 800; 
    letter-spacing: 0.02em; 
    text-transform: uppercase; 
    color: #1a1a1a !important; 
    display: flex; 
    align-items: center; 
    justify-content: space-between; 
    border-bottom: 2px solid #f3f4f6; 
    padding-bottom: 12px; 
}
.wazuh-stats-widget h4::before { 
    content: ""; 
    display: inline-block; 
    width: 10px; 
    height: 10px; 
    background-color: #009fe3; 
    border-radius: 50%; 
    margin-right: 10px; 
    box-shadow: 0 0 8px rgba(0, 159, 227, 0.6); 
    animation: wazuh-pulse 2s infinite; 
}
.wazuh-total-badge { 
    font-size: 0.75rem; 
    background: #e5e7eb; 
    padding: 4px 10px; 
    border-radius: 20px; 
    color: #4b5563; 
    font-weight: 700; 
    margin-left: auto; 
}
@keyframes wazuh-pulse { 
    0% { opacity: 1; } 
    50% { opacity: 0.5; } 
    100% { opacity: 1; } 
}

.wz-section-title { 
    margin: 0 0 10px 0; 
    font-size: 0.75rem; 
    color: #6b7280; 
    text-transform: uppercase; 
    font-weight: 700; 
    letter-spacing: 0.05em; 
}

/* Master Flex Layouts */
.wz-master-layout { 
    display: flex; 
    gap: 20px; 
    align-items: flex-start; 
    max-width: 100%; 
}
.wz-sidebar-severities { 
    width: 240px; 
    flex-shrink: 0; 
    background: #f4f5f7; 
    padding: 14px; 
    border-radius: 12px; 
}
.wz-main-grid { 
    flex: 1; 
    display: flex; 
    flex-direction: column; 
    gap: 16px; 
    min-width: 0; 
    max-width: 100%; 
}
.wz-sub-row { 
    display: flex; 
    gap: 16px; 
    width: 100%; 
    max-width: 100%; 
}
.wz-card { 
    flex: 1; 
    background: #f4f5f7; 
    padding: 14px; 
    border-radius: 12px; 
    min-width: 0; 
    max-width: 100%; 
}
.wz-full-card { 
    width: 100%; 
    max-width: 100%; 
}

/* Severity Stack Styling */
.wazuh-stats-widget ul.wz-severities-stack { 
    display: flex !important; 
    flex-direction: column !important; 
    gap: 8px !important; 
    list-style: none !important; 
    padding: 0 !important; 
    margin: 0 !important; 
}
.wz-severities-stack li { 
    display: flex !important; 
    justify-content: space-between !important; 
    align-items: center !important; 
    padding: 10px 12px !important; 
    background: #ffffff !important; 
    border-radius: 8px !important; 
    font-size: 0.8rem !important; 
    font-weight: 600 !important; 
    border-left: 4px solid #e5e7eb !important; 
    color: #1a1a1a !important; 
}
.wz-severities-stack li.wz-critical { border-left-color: #ef4444 !important; } 
.wz-severities-stack li.wz-high { border-left-color: #f97316 !important; } 
.wz-severities-stack li.wz-medium { border-left-color: #facc15 !important; } 
.wz-severities-stack li.wz-low { border-left-color: #009fe3 !important; }
.wz-severities-stack .wz-count { 
    background-color: #1a1a1a; 
    color: #ffffff; 
    padding: 2px 8px; 
    border-radius: 6px; 
    font-weight: 700; 
    font-size: 0.85rem; 
    width: 45px; 
    text-align: center; 
}

/* Text List Styling & Wrapping */
.wazuh-stats-widget ul.wz-text-list { 
    display: flex !important; 
    flex-direction: column !important; 
    gap: 0 !important; 
    list-style: none !important; 
    padding: 0 !important; 
    margin: 0 !important; 
    width: 100%; 
}
.wz-text-list li { 
    display: flex !important; 
    flex-direction: row !important; 
    justify-content: space-between !important; 
    align-items: center !important; 
    font-size: 0.8rem !important; 
    font-weight: 500 !important; 
    padding: 10px 0 !important; 
    border-bottom: 2px solid #e5e7eb !important; 
    background: transparent !important; 
    color: #1a1a1a !important; 
    width: 100%; 
}
.wz-text-list li:last-child { 
    border-bottom: none !important; 
    padding-bottom: 0 !important; 
}
.wz-text-list li > span:first-child { 
    flex: 1; 
    padding-right: 12px; 
    text-align: left; 
    word-break: break-word; 
    overflow-wrap: break-word; 
    white-space: normal; 
}
.wz-text-list li > span:last-child { 
    font-weight: 700 !important; 
    background: #ffffff !important; 
    padding: 4px 0 !important; 
    border-radius: 10px !important; 
    font-size: 0.75rem !important; 
    flex-shrink: 0 !important; 
    width: 60px !important; 
    text-align: center !important; 
    display: inline-block !important; 
    margin-left: auto !important; 
}

/* Mobile Responsiveness */
@media (max-width: 768px) {
    .wazuh-stats-widget { padding: 16px; }
    .wz-master-layout { flex-direction: column; }
    .wz-sidebar-severities { width: 100%; margin-bottom: 10px; }
    .wz-main-grid { width: 100%; }
    .wz-sub-row { flex-direction: column; gap: 16px; width: 100%; }
    .wazuh-stats-widget h4 { flex-direction: column; align-items: flex-start; gap: 12px; }
    .wazuh-total-badge { margin-left: 0; }
}