Saltar a contenido

Squert

Squert Cheat Sheet

__HTML_TAG_17_ Todos los comandos

Overview

Squert es una aplicación web diseñada para proporcionar una interfaz visual para los eventos de consulta y análisis almacenados en una base de datos Sguil. Desarrollado como una herramienta complementaria de la interfaz de cliente tradicional de Sguil, Squert ofrece a los analistas de seguridad una plataforma intuitiva basada en la web para investigar incidentes de seguridad de la red y realizar análisis de correlación de eventos. La aplicación aprovecha las tecnologías web modernas para presentar datos de eventos de seguridad en gráficos interactivos, gráficos y tablas, facilitando a los analistas identificar patrones, tendencias y anomalías en el tráfico de red.

La fuerza básica de Squert radica en su capacidad de transformar los datos de eventos de seguridad cruda en visualizaciones significativas que faciliten el análisis rápido de amenazas y la respuesta a incidentes. A diferencia de las herramientas tradicionales de seguridad basadas en comandos o escritorio, Squert proporciona una interfaz web receptiva que se puede acceder desde cualquier navegador moderno, permitiendo a los equipos de seguridad distribuidos colaborar eficazmente en actividades de investigación de incidentes y caza de amenazas. La aplicación se integra perfectamente con las implementaciones Sguil existentes, utilizando el mismo backend de la base de datos MySQL al tiempo que proporciona una mayor capacidad de visualización y análisis.

La arquitectura de Squert se construye alrededor de las tecnologías PHP y JavaScript, con el objetivo de proporcionar acceso en tiempo real a los datos de eventos de seguridad a través de interfaces web dinámicas. La aplicación soporta características avanzadas de filtrado, búsqueda y correlación que permiten a los analistas profundizar en eventos específicos, investigar actividades relacionadas y generar informes completos para fines de gestión y cumplimiento. Con su énfasis en usabilidad y análisis visual, Squert se ha convertido en un componente esencial de muchos centros de operaciones de seguridad que buscan modernizar sus flujos de trabajo de respuesta a incidentes.

Instalación

Ubuntu/Debian Instalación

Instalación de Squert en sistemas Ubuntu/Debian:

# Update system packages
sudo apt update && sudo apt upgrade -y

# Install required dependencies
sudo apt install -y apache2 php php-mysql php-gd php-curl php-json \
    php-xml php-mbstring libapache2-mod-php mysql-client git wget curl

# Enable Apache modules
sudo a2enmod rewrite
sudo a2enmod ssl

# Download Squert
cd /var/www
sudo git clone https://github.com/int13h/squert.git
sudo chown -R www-data:www-data squert

# Create Squert configuration directory
sudo mkdir -p /etc/squert
sudo chown www-data:www-data /etc/squert

# Set proper permissions
sudo chmod 755 /var/www/squert
sudo chmod -R 644 /var/www/squert/*
sudo chmod 755 /var/www/squert/scripts

# Create Apache virtual host
sudo cat > /etc/apache2/sites-available/squert.conf << 'EOF'
<VirtualHost *:80>
    ServerName squert.local
    DocumentRoot /var/www/squert

    <Directory /var/www/squert>
        Options -Indexes
        AllowOverride All
        Require all granted
    </Directory>

    # Security headers
    Header always set X-Content-Type-Options nosniff
    Header always set X-Frame-Options DENY
    Header always set X-XSS-Protection "1; mode=block"

    ErrorLog $\\\\{APACHE_LOG_DIR\\\\}/squert_error.log
    CustomLog $\\\\{APACHE_LOG_DIR\\\\}/squert_access.log combined
</VirtualHost>
EOF

# Enable site and restart Apache
sudo a2ensite squert.conf
sudo systemctl restart apache2

# Create database user for Squert
mysql -u root -p ``<< 'EOF'
CREATE USER 'squert'@'localhost' IDENTIFIED BY 'squertpassword';
GRANT SELECT ON sguildb.* TO 'squert'@'localhost';
FLUSH PRIVILEGES;
EOF

CentOS/RHEL Instalación

# Install EPEL repository
sudo yum install -y epel-release

# Install required packages
sudo yum install -y httpd php php-mysql php-gd php-curl php-json \
    php-xml php-mbstring mysql git wget curl

# Start and enable Apache
sudo systemctl start httpd
sudo systemctl enable httpd

# Download Squert
cd /var/www/html
sudo git clone https://github.com/int13h/squert.git
sudo chown -R apache:apache squert

# Create configuration directory
sudo mkdir -p /etc/squert
sudo chown apache:apache /etc/squert

# Configure SELinux (if enabled)
sudo setsebool -P httpd_can_network_connect 1
sudo setsebool -P httpd_can_network_connect_db 1

# Create Apache configuration
sudo cat >`` /etc/httpd/conf.d/squert.conf << 'EOF'
Alias /squert /var/www/html/squert

<Directory "/var/www/html/squert">
    Options -Indexes
    AllowOverride All
    Require all granted
</Directory>
EOF

# Restart Apache
sudo systemctl restart httpd

# Configure firewall
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Docker Instalación

Running Squert en contenedores Docker:

# Create Docker network
docker network create squert-network

# Create Squert container
cat > Dockerfile.squert << 'EOF'
FROM php:7.4-apache

# Install required PHP extensions
RUN docker-php-ext-install mysqli pdo pdo_mysql gd

# Install additional packages
RUN apt-get update && apt-get install -y \
    git \
    && rm -rf /var/lib/apt/lists/*

# Clone Squert
RUN git clone https://github.com/int13h/squert.git /var/www/html/squert

# Set permissions
RUN chown -R www-data:www-data /var/www/html/squert
RUN chmod -R 755 /var/www/html/squert

# Create configuration directory
RUN mkdir -p /etc/squert && chown www-data:www-data /etc/squert

# Apache configuration
COPY squert.conf /etc/apache2/sites-available/
RUN a2ensite squert && a2enmod rewrite

EXPOSE 80

CMD ["apache2-foreground"]
EOF

# Create Apache configuration for container
cat > squert.conf << 'EOF'
<VirtualHost *:80>
    DocumentRoot /var/www/html/squert

    <Directory /var/www/html/squert>
        Options -Indexes
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog $\\\\{APACHE_LOG_DIR\\\\}/squert_error.log
    CustomLog $\\\\{APACHE_LOG_DIR\\\\}/squert_access.log combined
</VirtualHost>
EOF

# Build and run Squert container
docker build -f Dockerfile.squert -t squert .
docker run -d --name squert \
    --network squert-network \
    -p 8080:80 \
    -v squert-config:/etc/squert \
    squert

# Connect to existing Sguil MySQL container
docker run -d --name squert-app \
    --network squert-network \
    -p 8080:80 \
    -e MYSQL_HOST=sguil-mysql \
    -e MYSQL_USER=squert \
    -e MYSQL_PASSWORD=squertpassword \
    -e MYSQL_DATABASE=sguildb \
    squert

Instalación manual

# Download latest Squert release
cd /tmp
wget https://github.com/int13h/squert/archive/master.tar.gz
tar -xzf master.tar.gz

# Copy to web directory
sudo cp -r squert-master /var/www/squert
sudo chown -R www-data:www-data /var/www/squert

# Set proper permissions
sudo find /var/www/squert -type f -exec chmod 644 \\\\{\\\\} \;
sudo find /var/www/squert -type d -exec chmod 755 \\\\{\\\\} \;
sudo chmod +x /var/www/squert/scripts/*

# Create symbolic link
sudo ln -s /var/www/squert /var/www/html/squert

# Create configuration directory
sudo mkdir -p /etc/squert
sudo chown www-data:www-data /etc/squert

Uso básico

Configuración inicial

Configuración de configuración Squert:

# Create Squert configuration file
sudo cat > /var/www/squert/.scripts/squert.inc << 'EOF'
<?php
// Squert Configuration

// Database configuration
$dbname = 'sguildb';
$dbhost = 'localhost';
$dbuser = 'squert';
$dbpass = 'squertpassword';
$dbport = 3306;

// Application settings
$squert_title = 'Squert - Network Security Monitoring';
$refresh_time = 300; // 5 minutes
$event_limit = 1000;

// Time zone
date_default_timezone_set('America/New_York');

// Security settings
$use_https = false;
$session_timeout = 3600; // 1 hour

// Chart settings
$chart_height = 400;
$chart_width = 800;

// IP geolocation (optional)
$use_geoip = false;
$geoip_db_path = '/usr/share/GeoIP/GeoLiteCity.dat';

// External links
$whois_provider = 'https://whois.net/ip/';
$reputation_provider = 'https://www.virustotal.com/gui/ip-address/';

// Custom CSS
$custom_css = '';

// Debug mode
$debug = false;
?>
EOF

# Set proper permissions
sudo chown www-data:www-data /var/www/squert/.scripts/squert.inc
sudo chmod 600 /var/www/squert/.scripts/squert.inc

# Create database tables for Squert
mysql -u squert -p sguildb << 'EOF'
-- Create Squert-specific tables
CREATE TABLE IF NOT EXISTS mappings (
    id INT AUTO_INCREMENT PRIMARY KEY,
    ip_src VARCHAR(15),
    ip_dst VARCHAR(15),
    hostname VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS filters (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    filter_text TEXT,
    user VARCHAR(50),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS bookmarks (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(200),
    url TEXT,
    user VARCHAR(50),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
EOF

Web Interface Access

Acceso y uso de la interfaz web Squert:

# Start Apache if not running
sudo systemctl start apache2

# Check Apache status
sudo systemctl status apache2

# Access Squert web interface
# Open browser and navigate to:
# http://your-server-ip/squert
# or
# http://localhost/squert

# Check Apache logs for any errors
sudo tail -f /var/log/apache2/squert_error.log
sudo tail -f /var/log/apache2/squert_access.log

# Test database connectivity
php -r "
\$conn = new mysqli('localhost', 'squert', 'squertpassword', 'sguildb');
if (\$conn->connect_error) \\\\{
    die('Connection failed: ' . \$conn->connect_error);
\\\\}
echo 'Database connection successful\n';
\$conn->close();
"

Basic Navigation

Comprender componentes de interfaz Squert:

# Main dashboard components:
# 1. Summary view - Overview of recent events
# 2. Events view - Detailed event listing
# 3. Charts view - Visual analytics
# 4. Search interface - Advanced filtering
# 5. Reports section - Generated reports

# Key interface elements:
# - Time range selector
# - Event filters
# - Source/destination IP analysis
# - Signature analysis
# - Protocol breakdown
# - Geographic mapping (if enabled)

# Common workflows:
# 1. Monitor real-time events
# 2. Investigate specific incidents
# 3. Analyze traffic patterns
# 4. Generate compliance reports
# 5. Correlate related events

Características avanzadas

Custom Dashboards

Creación de paneles y vistas personalizadas:

<?php
// Custom dashboard configuration
// File: /var/www/squert/custom_dashboard.php

require_once '.scripts/squert.inc';

class CustomDashboard \\\\{
    private $db;

    public function __construct() \\\\{
        global $dbhost, $dbuser, $dbpass, $dbname;
        $this->db = new mysqli($dbhost, $dbuser, $dbpass, $dbname);

        if ($this->db->connect_error) \\\\{
            die("Connection failed: " . $this->db->connect_error);
        \\\\}
    \\\\}

    public function getTopAttackers($limit = 10, $hours = 24) \\\\{
        $query = "
            SELECT
                src_ip,
                COUNT(*) as event_count,
                COUNT(DISTINCT dst_ip) as target_count,
                COUNT(DISTINCT signature_id) as signature_count,
                MIN(timestamp) as first_seen,
                MAX(timestamp) as last_seen
            FROM event
            WHERE timestamp >= DATE_SUB(NOW(), INTERVAL ? HOUR)
            GROUP BY src_ip
            ORDER BY event_count DESC
            LIMIT ?
        ";

        $stmt = $this->db->prepare($query);
        $stmt->bind_param("ii", $hours, $limit);
        $stmt->execute();

        return $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    \\\\}

    public function getTopTargets($limit = 10, $hours = 24) \\\\{
        $query = "
            SELECT
                dst_ip,
                COUNT(*) as event_count,
                COUNT(DISTINCT src_ip) as attacker_count,
                COUNT(DISTINCT signature_id) as signature_count,
                MIN(timestamp) as first_seen,
                MAX(timestamp) as last_seen
            FROM event
            WHERE timestamp >= DATE_SUB(NOW(), INTERVAL ? HOUR)
            GROUP BY dst_ip
            ORDER BY event_count DESC
            LIMIT ?
        ";

        $stmt = $this->db->prepare($query);
        $stmt->bind_param("ii", $hours, $limit);
        $stmt->execute();

        return $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    \\\\}

    public function getSignatureStats($hours = 24) \\\\{
        $query = "
            SELECT
                signature,
                signature_id,
                COUNT(*) as event_count,
                COUNT(DISTINCT src_ip) as unique_sources,
                COUNT(DISTINCT dst_ip) as unique_targets
            FROM event
            WHERE timestamp >= DATE_SUB(NOW(), INTERVAL ? HOUR)
            GROUP BY signature, signature_id
            ORDER BY event_count DESC
            LIMIT 20
        ";

        $stmt = $this->db->prepare($query);
        $stmt->bind_param("i", $hours);
        $stmt->execute();

        return $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    \\\\}

    public function getHourlyEventCounts($hours = 24) \\\\{
        $query = "
            SELECT
                DATE_FORMAT(timestamp, '%Y-%m-%d %H:00:00') as hour,
                COUNT(*) as event_count
            FROM event
            WHERE timestamp >= DATE_SUB(NOW(), INTERVAL ? HOUR)
            GROUP BY DATE_FORMAT(timestamp, '%Y-%m-%d %H:00:00')
            ORDER BY hour
        ";

        $stmt = $this->db->prepare($query);
        $stmt->bind_param("i", $hours);
        $stmt->execute();

        return $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    \\\\}

    public function generateDashboardHTML() \\\\{
        $topAttackers = $this->getTopAttackers();
        $topTargets = $this->getTopTargets();
        $signatureStats = $this->getSignatureStats();
        $hourlyStats = $this->getHourlyEventCounts();

        ob_start();
        ?>
        <!DOCTYPE html>
        <html>
        <head>
            <title>Custom Security Dashboard</title>
            <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
            <style>
                body \\\\{ font-family: Arial, sans-serif; margin: 20px; \\\\}
                .dashboard-grid \\\\{ display: grid; grid-template-columns: 1fr 1fr; gap: 20px; \\\\}
                .widget \\\\{ border: 1px solid #ddd; padding: 15px; border-radius: 5px; \\\\}
                .widget h3 \\\\{ margin-top: 0; color: #333; \\\\}
                table \\\\{ width: 100%; border-collapse: collapse; \\\\}
                th, td \\\\{ padding: 8px; text-align: left; border-bottom: 1px solid #ddd; \\\\}
                th \\\\{ background-color: #f2f2f2; \\\\}
                .chart-container \\\\{ width: 100%; height: 300px; \\\\}
            </style>
        </head>
        <body>
            <h1>Security Operations Dashboard</h1>
            <p>Last updated: <?php echo date('Y-m-d H:i:s'); ?></p>

            <div class="dashboard-grid">
                <div class="widget">
                    <h3>Top Attackers (24h)</h3>
                    <table>
                        <tr><th>Source IP</th><th>Events</th><th>Targets</th><th>Signatures</th></tr>
                        <?php foreach ($topAttackers as $attacker): ?>
                        <tr>
                            <td><?php echo htmlspecialchars($attacker['src_ip']); ?></td>
                            <td><?php echo $attacker['event_count']; ?></td>
                            <td><?php echo $attacker['target_count']; ?></td>
                            <td><?php echo $attacker['signature_count']; ?></td>
                        </tr>
                        <?php endforeach; ?>
                    </table>
                </div>

                <div class="widget">
                    <h3>Top Targets (24h)</h3>
                    <table>
                        <tr><th>Target IP</th><th>Events</th><th>Attackers</th><th>Signatures</th></tr>
                        <?php foreach ($topTargets as $target): ?>
                        <tr>
                            <td><?php echo htmlspecialchars($target['dst_ip']); ?></td>
                            <td><?php echo $target['event_count']; ?></td>
                            <td><?php echo $target['attacker_count']; ?></td>
                            <td><?php echo $target['signature_count']; ?></td>
                        </tr>
                        <?php endforeach; ?>
                    </table>
                </div>

                <div class="widget">
                    <h3>Event Timeline (24h)</h3>
                    <div class="chart-container">
                        <canvas id="timelineChart"></canvas>
                    </div>
                </div>

                <div class="widget">
                    <h3>Top Signatures (24h)</h3>
                    <table>
                        <tr><th>Signature</th><th>Events</th><th>Sources</th></tr>
                        <?php foreach (array_slice($signatureStats, 0, 10) as $sig): ?>
                        <tr>
                            <td><?php echo htmlspecialchars(substr($sig['signature'], 0, 50)) . '...'; ?></td>
                            <td><?php echo $sig['event_count']; ?></td>
                            <td><?php echo $sig['unique_sources']; ?></td>
                        </tr>
                        <?php endforeach; ?>
                    </table>
                </div>
            </div>

            <script>
                // Timeline chart
                const ctx = document.getElementById('timelineChart').getContext('2d');
                const timelineData = <?php echo json_encode($hourlyStats); ?>;

                new Chart(ctx, \\\\{
                    type: 'line',
                    data: \\\\{
                        labels: timelineData.map(item => item.hour),
                        datasets: [\\\\{
                            label: 'Events per Hour',
                            data: timelineData.map(item => item.event_count),
                            borderColor: 'rgb(75, 192, 192)',
                            tension: 0.1
                        \\\\}]
                    \\\\},
                    options: \\\\{
                        responsive: true,
                        maintainAspectRatio: false,
                        scales: \\\\{
                            y: \\\\{
                                beginAtZero: true
                            \\\\}
                        \\\\}
                    \\\\}
                \\\\});
            </script>
        </body>
        </html>
        <?php
        return ob_get_clean();
    \\\\}
\\\\}

// Generate and display dashboard
$dashboard = new CustomDashboard();
echo $dashboard->generateDashboardHTML();
?>

Filtro avanzado y búsqueda

Creación de capacidades avanzadas de búsqueda y filtrado:

// Advanced search interface
// File: /var/www/squert/js/advanced_search.js

class AdvancedSearch \\\\{
    constructor() \\\\{
        this.filters = [];
        this.initializeInterface();
    \\\\}

    initializeInterface() \\\\{
        this.createSearchForm();
        this.bindEvents();
    \\\\}

    createSearchForm() \\\\{
        const searchContainer = document.getElementById('advanced-search');

        searchContainer.innerHTML = `
            <div class="search-form">
                <h3>Advanced Event Search</h3>

                <div class="filter-group">
                    <label>Time Range:</label>
                    <select id="time-range">
                        <option value="1h">Last Hour</option>
                        <option value="6h">Last 6 Hours</option>
                        <option value="24h">Last 24 Hours</option>
                        <option value="7d">Last 7 Days</option>
                        <option value="30d">Last 30 Days</option>
                        <option value="custom">Custom Range</option>
                    </select>
                </div>

                <div class="filter-group" id="custom-time" style="display:none;">
                    <label>From:</label>
                    <input type="datetime-local" id="start-time">
                    <label>To:</label>
                    <input type="datetime-local" id="end-time">
                </div>

                <div class="filter-group">
                    <label>Source IP:</label>
                    <input type="text" id="src-ip" placeholder="192.168.1.1 or 192.168.1.0/24">
                </div>

                <div class="filter-group">
                    <label>Destination IP:</label>
                    <input type="text" id="dst-ip" placeholder="10.0.0.1 or 10.0.0.0/16">
                </div>

                <div class="filter-group">
                    <label>Port Range:</label>
                    <input type="text" id="port-range" placeholder="80,443,8080-8090">
                </div>

                <div class="filter-group">
                    <label>Signature:</label>
                    <input type="text" id="signature" placeholder="Search signature text">
                </div>

                <div class="filter-group">
                    <label>Signature ID:</label>
                    <input type="text" id="signature-id" placeholder="1,2,3 or 100-200">
                </div>

                <div class="filter-group">
                    <label>Protocol:</label>
                    <select id="protocol">
                        <option value="">All Protocols</option>
                        <option value="1">ICMP</option>
                        <option value="6">TCP</option>
                        <option value="17">UDP</option>
                    </select>
                </div>

                <div class="filter-group">
                    <label>Event Limit:</label>
                    <select id="event-limit">
                        <option value="100">100 events</option>
                        <option value="500">500 events</option>
                        <option value="1000">1000 events</option>
                        <option value="5000">5000 events</option>
                    </select>
                </div>

                <div class="filter-actions">
                    <button id="search-btn" class="btn-primary">Search Events</button>
                    <button id="save-filter-btn" class="btn-secondary">Save Filter</button>
                    <button id="clear-btn" class="btn-secondary">Clear All</button>
                </div>

                <div id="saved-filters">
                    <h4>Saved Filters</h4>
                    <div id="filter-list"></div>
                </div>
            </div>

            <div id="search-results">
                <div id="results-summary"></div>
                <div id="results-table"></div>
            </div>
        `;
    \\\\}

    bindEvents() \\\\{
        // Time range change
        document.getElementById('time-range').addEventListener('change', (e) => \\\\{
            const customTime = document.getElementById('custom-time');
            customTime.style.display = e.target.value === 'custom' ? 'block' : 'none';
        \\\\});

        // Search button
        document.getElementById('search-btn').addEventListener('click', () => \\\\{
            this.performSearch();
        \\\\});

        // Save filter button
        document.getElementById('save-filter-btn').addEventListener('click', () => \\\\{
            this.saveCurrentFilter();
        \\\\});

        // Clear button
        document.getElementById('clear-btn').addEventListener('click', () => \\\\{
            this.clearAllFilters();
        \\\\});

        // Load saved filters
        this.loadSavedFilters();
    \\\\}

    buildSearchQuery() \\\\{
        const filters = [];

        // Time range
        const timeRange = document.getElementById('time-range').value;
        if (timeRange !== 'custom') \\\\{
            filters.push(`timestamp >= DATE_SUB(NOW(), INTERVAL $\\{timeRange.replace(/[hd]/, timeRange.includes('h') ? ' HOUR' : ' DAY')\\})`);
        \\\\} else \\\\{
            const startTime = document.getElementById('start-time').value;
            const endTime = document.getElementById('end-time').value;
            if (startTime) filters.push(`timestamp >= '$\\{startTime\\}'`);
            if (endTime) filters.push(`timestamp <= '$\\{endTime\\}'`);
        \\\\}

        // IP addresses
        const srcIp = document.getElementById('src-ip').value.trim();
        if (srcIp) \\\\{
            if (srcIp.includes('/')) \\\\{
                // CIDR notation
                filters.push(`INET_ATON(src_ip) & INET_ATON('$\\{srcIp.split('/')[1]\\}') = INET_ATON('$\\{srcIp.split('/')[0]\\}')`);
            \\\\} else \\\\{
                filters.push(`src_ip = '$\\{srcIp\\}'`);
            \\\\}
        \\\\}

        const dstIp = document.getElementById('dst-ip').value.trim();
        if (dstIp) \\\\{
            if (dstIp.includes('/')) \\\\{
                filters.push(`INET_ATON(dst_ip) & INET_ATON('$\\{dstIp.split('/')[1]\\}') = INET_ATON('$\\{dstIp.split('/')[0]\\}')`);
            \\\\} else \\\\{
                filters.push(`dst_ip = '$\\{dstIp\\}'`);
            \\\\}
        \\\\}

        // Ports
        const portRange = document.getElementById('port-range').value.trim();
        if (portRange) \\\\{
            const portConditions = [];
            portRange.split(',').forEach(port => \\\\{
                if (port.includes('-')) \\\\{
                    const [start, end] = port.split('-');
                    portConditions.push(`(src_port BETWEEN $\\{start\\} AND $\\{end\\}) OR (dst_port BETWEEN $\\{start\\} AND $\\{end\\})`);
                \\\\} else \\\\{
                    portConditions.push(`src_port = $\\{port\\} OR dst_port = $\\{port\\}`);
                \\\\}
            \\\\});
            filters.push(`($\\{portConditions.join(' OR ')\\})`);
        \\\\}

        // Signature
        const signature = document.getElementById('signature').value.trim();
        if (signature) \\\\{
            filters.push(`signature LIKE '%$\\{signature\\}%'`);
        \\\\}

        // Signature ID
        const signatureId = document.getElementById('signature-id').value.trim();
        if (signatureId) \\\\{
            if (signatureId.includes('-')) \\\\{
                const [start, end] = signatureId.split('-');
                filters.push(`signature_id BETWEEN $\\{start\\} AND $\\{end\\}`);
            \\\\} else if (signatureId.includes(',')) \\\\{
                filters.push(`signature_id IN ($\\{signatureId\\})`);
            \\\\} else \\\\{
                filters.push(`signature_id = $\\{signatureId\\}`);
            \\\\}
        \\\\}

        // Protocol
        const protocol = document.getElementById('protocol').value;
        if (protocol) \\\\{
            filters.push(`ip_proto = $\\{protocol\\}`);
        \\\\}

        return filters.join(' AND ');
    \\\\}

    async performSearch() \\\\{
        const whereClause = this.buildSearchQuery();
        const limit = document.getElementById('event-limit').value;

        const query = `
            SELECT
                sid, cid, timestamp, src_ip, src_port, dst_ip, dst_port,
                ip_proto, signature, signature_id
            FROM event
            $\\{whereClause ? 'WHERE ' + whereClause : ''\\}
            ORDER BY timestamp DESC
            LIMIT $\\{limit\\}
        `;

        try \\\\{
            const response = await fetch('search_events.php', \\\\{
                method: 'POST',
                headers: \\\\{
                    'Content-Type': 'application/json',
                \\\\},
                body: JSON.stringify(\\\\{ query: query \\\\})
            \\\\});

            const results = await response.json();
            this.displayResults(results);

        \\\\} catch (error) \\\\{
            console.error('Search failed:', error);
            this.displayError('Search failed: ' + error.message);
        \\\\}
    \\\\}

    displayResults(results) \\\\{
        const summaryDiv = document.getElementById('results-summary');
        const tableDiv = document.getElementById('results-table');

        summaryDiv.innerHTML = `
            <h3>Search Results</h3>
            <p>Found $\\{results.length\\} events</p>
        `;

        if (results.length === 0) \\\\{
            tableDiv.innerHTML = '<p>No events found matching the search criteria.</p>';
            return;
        \\\\}

        let tableHTML = `
            <table class="results-table">
                <thead>
                    <tr>
                        <th>Timestamp</th>
                        <th>Source</th>
                        <th>Destination</th>
                        <th>Protocol</th>
                        <th>Signature</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
        `;

        results.forEach(event => \\\\{
            tableHTML += `
                <tr>
                    <td>$\\{event.timestamp\\}</td>
                    <td>$\\{event.src_ip\\}:$\\{event.src_port\\}</td>
                    <td>$\\{event.dst_ip\\}:$\\{event.dst_port\\}</td>
                    <td>$\\{this.getProtocolName(event.ip_proto)\\}</td>
                    <td title="$\\{event.signature\\}">$\\{event.signature.substring(0, 50)\\}...</td>
                    <td>
                        <button onclick="viewEventDetails($\\{event.sid\\}, $\\{event.cid\\})">Details</button>
                        <button onclick="investigateIP('$\\{event.src_ip\\}')">Investigate</button>
                    </td>
                </tr>
            `;
        \\\\});

        tableHTML += '</tbody></table>';
        tableDiv.innerHTML = tableHTML;
    \\\\}

    getProtocolName(proto) \\\\{
        const protocols = \\\\{ 1: 'ICMP', 6: 'TCP', 17: 'UDP' \\\\};
        return protocols[proto]||proto;
    \\\\}

    saveCurrentFilter() \\\\{
        const filterName = prompt('Enter a name for this filter:');
        if (!filterName) return;

        const filterData = \\\\{
            name: filterName,
            timeRange: document.getElementById('time-range').value,
            srcIp: document.getElementById('src-ip').value,
            dstIp: document.getElementById('dst-ip').value,
            portRange: document.getElementById('port-range').value,
            signature: document.getElementById('signature').value,
            signatureId: document.getElementById('signature-id').value,
            protocol: document.getElementById('protocol').value,
            limit: document.getElementById('event-limit').value
        \\\\};

        // Save to localStorage
        const savedFilters = JSON.parse(localStorage.getItem('squert_filters')||'[]');
        savedFilters.push(filterData);
        localStorage.setItem('squert_filters', JSON.stringify(savedFilters));

        this.loadSavedFilters();
    \\\\}

    loadSavedFilters() \\\\{
        const savedFilters = JSON.parse(localStorage.getItem('squert_filters')||'[]');
        const filterList = document.getElementById('filter-list');

        filterList.innerHTML = '';

        savedFilters.forEach((filter, index) => \\\\{
            const filterDiv = document.createElement('div');
            filterDiv.className = 'saved-filter';
            filterDiv.innerHTML = `
                <span>$\\{filter.name\\}</span>
                <button onclick="loadFilter($\\{index\\})">Load</button>
                <button onclick="deleteFilter($\\{index\\})">Delete</button>
            `;
            filterList.appendChild(filterDiv);
        \\\\});
    \\\\}

    clearAllFilters() \\\\{
        document.getElementById('time-range').value = '24h';
        document.getElementById('src-ip').value = '';
        document.getElementById('dst-ip').value = '';
        document.getElementById('port-range').value = '';
        document.getElementById('signature').value = '';
        document.getElementById('signature-id').value = '';
        document.getElementById('protocol').value = '';
        document.getElementById('event-limit').value = '1000';
        document.getElementById('custom-time').style.display = 'none';
    \\\\}
\\\\}

// Initialize advanced search when page loads
document.addEventListener('DOMContentLoaded', () => \\\\{
    new AdvancedSearch();
\\\\});

// Global functions for event handling
function viewEventDetails(sid, cid) \\\\{
    window.open(`event_details.php?sid=$\\{sid\\}&cid=$\\{cid\\}`, '_blank');
\\\\}

function investigateIP(ip) \\\\{
    window.open(`ip_investigation.php?ip=$\\{ip\\}`, '_blank');
\\\\}

function loadFilter(index) \\\\{
    const savedFilters = JSON.parse(localStorage.getItem('squert_filters')||'[]');
    const filter = savedFilters[index];

    if (filter) \\\\{
        document.getElementById('time-range').value = filter.timeRange;
        document.getElementById('src-ip').value = filter.srcIp;
        document.getElementById('dst-ip').value = filter.dstIp;
        document.getElementById('port-range').value = filter.portRange;
        document.getElementById('signature').value = filter.signature;
        document.getElementById('signature-id').value = filter.signatureId;
        document.getElementById('protocol').value = filter.protocol;
        document.getElementById('event-limit').value = filter.limit;
    \\\\}
\\\\}

function deleteFilter(index) \\\\{
    if (confirm('Are you sure you want to delete this filter?')) \\\\{
        const savedFilters = JSON.parse(localStorage.getItem('squert_filters')||'[]');
        savedFilters.splice(index, 1);
        localStorage.setItem('squert_filters', JSON.stringify(savedFilters));

        // Reload the filter list
        const search = new AdvancedSearch();
        search.loadSavedFilters();
    \\\\}
\\\\}

Automated Reporting

Creación de capacidades automatizadas de presentación de informes:

<?php
// Automated reporting system
// File: /var/www/squert/reports/automated_reports.php

require_once '../.scripts/squert.inc';

class AutomatedReports \\\\{
    private $db;
    private $config;

    public function __construct() \\\\{
        global $dbhost, $dbuser, $dbpass, $dbname;

        $this->db = new mysqli($dbhost, $dbuser, $dbpass, $dbname);
        if ($this->db->connect_error) \\\\{
            die("Connection failed: " . $this->db->connect_error);
        \\\\}

        $this->config = [
            'report_dir' => '/var/www/squert/reports/generated',
            'email_reports' => true,
            'email_to' => 'security@company.com',
            'email_from' => 'squert@company.com'
        ];

        // Create reports directory if it doesn't exist
        if (!is_dir($this->config['report_dir'])) \\\\{
            mkdir($this->config['report_dir'], 0755, true);
        \\\\}
    \\\\}

    public function generateDailyReport($date = null) \\\\{
        if (!$date) \\\\{
            $date = date('Y-m-d', strtotime('-1 day'));
        \\\\}

        $report_data = [
            'date' => $date,
            'summary' => $this->getDailySummary($date),
            'top_attackers' => $this->getTopAttackers($date),
            'top_targets' => $this->getTopTargets($date),
            'top_signatures' => $this->getTopSignatures($date),
            'hourly_stats' => $this->getHourlyStats($date),
            'protocol_breakdown' => $this->getProtocolBreakdown($date),
            'geographic_analysis' => $this->getGeographicAnalysis($date)
        ];

        $html_report = $this->generateHTMLReport($report_data, 'daily');
        $pdf_report = $this->generatePDFReport($report_data, 'daily');

        // Save reports
        $html_file = $this->config['report_dir'] . "/daily_report_\\\\{$date\\\\}.html";
        $pdf_file = $this->config['report_dir'] . "/daily_report_\\\\{$date\\\\}.pdf";

        file_put_contents($html_file, $html_report);
        file_put_contents($pdf_file, $pdf_report);

        // Email report if configured
        if ($this->config['email_reports']) \\\\{
            $this->emailReport($html_file, $pdf_file, "Daily Security Report - \\\\{$date\\\\}");
        \\\\}

        return [
            'html_file' => $html_file,
            'pdf_file' => $pdf_file,
            'data' => $report_data
        ];
    \\\\}

    public function generateWeeklyReport($week_start = null) \\\\{
        if (!$week_start) \\\\{
            $week_start = date('Y-m-d', strtotime('last monday'));
        \\\\}

        $week_end = date('Y-m-d', strtotime($week_start . ' +6 days'));

        $report_data = [
            'week_start' => $week_start,
            'week_end' => $week_end,
            'summary' => $this->getWeeklySummary($week_start, $week_end),
            'trends' => $this->getWeeklyTrends($week_start, $week_end),
            'top_incidents' => $this->getTopIncidents($week_start, $week_end),
            'security_metrics' => $this->getSecurityMetrics($week_start, $week_end)
        ];

        $html_report = $this->generateHTMLReport($report_data, 'weekly');

        $html_file = $this->config['report_dir'] . "/weekly_report_\\\\{$week_start\\\\}_to_\\\\{$week_end\\\\}.html";
        file_put_contents($html_file, $html_report);

        return ['html_file' => $html_file, 'data' => $report_data];
    \\\\}

    private function getDailySummary($date) \\\\{
        $query = "
            SELECT
                COUNT(*) as total_events,
                COUNT(DISTINCT src_ip) as unique_sources,
                COUNT(DISTINCT dst_ip) as unique_targets,
                COUNT(DISTINCT signature_id) as unique_signatures,
                MIN(timestamp) as first_event,
                MAX(timestamp) as last_event
            FROM event
            WHERE DATE(timestamp) = ?
        ";

        $stmt = $this->db->prepare($query);
        $stmt->bind_param("s", $date);
        $stmt->execute();

        return $stmt->get_result()->fetch_assoc();
    \\\\}

    private function getTopAttackers($date, $limit = 10) \\\\{
        $query = "
            SELECT
                src_ip,
                COUNT(*) as event_count,
                COUNT(DISTINCT dst_ip) as target_count,
                COUNT(DISTINCT signature_id) as signature_count,
                GROUP_CONCAT(DISTINCT signature ORDER BY signature LIMIT 3) as top_signatures
            FROM event
            WHERE DATE(timestamp) = ?
            GROUP BY src_ip
            ORDER BY event_count DESC
            LIMIT ?
        ";

        $stmt = $this->db->prepare($query);
        $stmt->bind_param("si", $date, $limit);
        $stmt->execute();

        return $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    \\\\}

    private function getTopTargets($date, $limit = 10) \\\\{
        $query = "
            SELECT
                dst_ip,
                COUNT(*) as event_count,
                COUNT(DISTINCT src_ip) as attacker_count,
                COUNT(DISTINCT signature_id) as signature_count
            FROM event
            WHERE DATE(timestamp) = ?
            GROUP BY dst_ip
            ORDER BY event_count DESC
            LIMIT ?
        ";

        $stmt = $this->db->prepare($query);
        $stmt->bind_param("si", $date, $limit);
        $stmt->execute();

        return $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    \\\\}

    private function getTopSignatures($date, $limit = 15) \\\\{
        $query = "
            SELECT
                signature,
                signature_id,
                COUNT(*) as event_count,
                COUNT(DISTINCT src_ip) as unique_sources,
                COUNT(DISTINCT dst_ip) as unique_targets
            FROM event
            WHERE DATE(timestamp) = ?
            GROUP BY signature, signature_id
            ORDER BY event_count DESC
            LIMIT ?
        ";

        $stmt = $this->db->prepare($query);
        $stmt->bind_param("si", $date, $limit);
        $stmt->execute();

        return $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    \\\\}

    private function getHourlyStats($date) \\\\{
        $query = "
            SELECT
                HOUR(timestamp) as hour,
                COUNT(*) as event_count
            FROM event
            WHERE DATE(timestamp) = ?
            GROUP BY HOUR(timestamp)
            ORDER BY hour
        ";

        $stmt = $this->db->prepare($query);
        $stmt->bind_param("s", $date);
        $stmt->execute();

        $results = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);

        // Fill in missing hours with 0 events
        $hourly_stats = array_fill(0, 24, 0);
        foreach ($results as $row) \\\\{
            $hourly_stats[$row['hour']] = $row['event_count'];
        \\\\}

        return $hourly_stats;
    \\\\}

    private function getProtocolBreakdown($date) \\\\{
        $query = "
            SELECT
                ip_proto,
                COUNT(*) as event_count,
                ROUND(COUNT(*) * 100.0 / (SELECT COUNT(*) FROM event WHERE DATE(timestamp) = ?), 2) as percentage
            FROM event
            WHERE DATE(timestamp) = ?
            GROUP BY ip_proto
            ORDER BY event_count DESC
        ";

        $stmt = $this->db->prepare($query);
        $stmt->bind_param("ss", $date, $date);
        $stmt->execute();

        return $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    \\\\}

    private function generateHTMLReport($data, $type) \\\\{
        ob_start();
        ?>
        <!DOCTYPE html>
        <html>
        <head>
            <title><?php echo ucfirst($type); ?> Security Report</title>
            <style>
                body \\\\{ font-family: Arial, sans-serif; margin: 20px; \\\\}
                .header \\\\{ background: #f4f4f4; padding: 20px; border-radius: 5px; \\\\}
                .summary \\\\{ display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin: 20px 0; \\\\}
                .metric \\\\{ background: #e9e9e9; padding: 15px; border-radius: 5px; text-align: center; \\\\}
                .metric h3 \\\\{ margin: 0; color: #333; \\\\}
                .metric .value \\\\{ font-size: 24px; font-weight: bold; color: #007cba; \\\\}
                table \\\\{ width: 100%; border-collapse: collapse; margin: 20px 0; \\\\}
                th, td \\\\{ padding: 10px; text-align: left; border-bottom: 1px solid #ddd; \\\\}
                th \\\\{ background-color: #f2f2f2; \\\\}
                .chart \\\\{ margin: 20px 0; \\\\}
                .section \\\\{ margin: 30px 0; \\\\}
                .section h2 \\\\{ color: #333; border-bottom: 2px solid #007cba; padding-bottom: 5px; \\\\}
            </style>
        </head>
        <body>
            <div class="header">
                <h1><?php echo ucfirst($type); ?> Security Report</h1>
                <?php if ($type == 'daily'): ?>
                    <p>Report Date: <?php echo $data['date']; ?></p>
                <?php else: ?>
                    <p>Report Period: <?php echo $data['week_start']; ?> to <?php echo $data['week_end']; ?></p>
                <?php endif; ?>
                <p>Generated: <?php echo date('Y-m-d H:i:s'); ?></p>
            </div>

            <?php if ($type == 'daily'): ?>
                <div class="summary">
                    <div class="metric">
                        <h3>Total Events</h3>
                        <div class="value"><?php echo number_format($data['summary']['total_events']); ?></div>
                    </div>
                    <div class="metric">
                        <h3>Unique Sources</h3>
                        <div class="value"><?php echo number_format($data['summary']['unique_sources']); ?></div>
                    </div>
                    <div class="metric">
                        <h3>Unique Targets</h3>
                        <div class="value"><?php echo number_format($data['summary']['unique_targets']); ?></div>
                    </div>
                    <div class="metric">
                        <h3>Unique Signatures</h3>
                        <div class="value"><?php echo number_format($data['summary']['unique_signatures']); ?></div>
                    </div>
                </div>

                <div class="section">
                    <h2>Top Attackers</h2>
                    <table>
                        <tr><th>Source IP</th><th>Events</th><th>Targets</th><th>Signatures</th></tr>
                        <?php foreach ($data['top_attackers'] as $attacker): ?>
                        <tr>
                            <td><?php echo htmlspecialchars($attacker['src_ip']); ?></td>
                            <td><?php echo number_format($attacker['event_count']); ?></td>
                            <td><?php echo number_format($attacker['target_count']); ?></td>
                            <td><?php echo number_format($attacker['signature_count']); ?></td>
                        </tr>
                        <?php endforeach; ?>
                    </table>
                </div>

                <div class="section">
                    <h2>Top Targets</h2>
                    <table>
                        <tr><th>Target IP</th><th>Events</th><th>Attackers</th><th>Signatures</th></tr>
                        <?php foreach ($data['top_targets'] as $target): ?>
                        <tr>
                            <td><?php echo htmlspecialchars($target['dst_ip']); ?></td>
                            <td><?php echo number_format($target['event_count']); ?></td>
                            <td><?php echo number_format($target['attacker_count']); ?></td>
                            <td><?php echo number_format($target['signature_count']); ?></td>
                        </tr>
                        <?php endforeach; ?>
                    </table>
                </div>

                <div class="section">
                    <h2>Top Signatures</h2>
                    <table>
                        <tr><th>Signature</th><th>Events</th><th>Sources</th><th>Targets</th></tr>
                        <?php foreach ($data['top_signatures'] as $sig): ?>
                        <tr>
                            <td><?php echo htmlspecialchars($sig['signature']); ?></td>
                            <td><?php echo number_format($sig['event_count']); ?></td>
                            <td><?php echo number_format($sig['unique_sources']); ?></td>
                            <td><?php echo number_format($sig['unique_targets']); ?></td>
                        </tr>
                        <?php endforeach; ?>
                    </table>
                </div>
            <?php endif; ?>
        </body>
        </html>
        <?php
        return ob_get_clean();
    \\\\}

    private function emailReport($html_file, $pdf_file, $subject) \\\\{
        // Implementation depends on your email system
        // This is a basic example using PHP mail()

        $to = $this->config['email_to'];
        $from = $this->config['email_from'];

        $headers = "From: \\\\{$from\\\\}\r\n";
        $headers .= "MIME-Version: 1.0\r\n";
        $headers .= "Content-Type: text/html; charset=UTF-8\r\n";

        $body = file_get_contents($html_file);

        mail($to, $subject, $body, $headers);
    \\\\}
\\\\}

// Usage example
if (php_sapi_name() === 'cli') \\\\{
    // Command line usage
    $reports = new AutomatedReports();

    $action = $argv[1] ?? 'daily';
    $date = $argv[2] ?? null;

    switch ($action) \\\\{
        case 'daily':
            $result = $reports->generateDailyReport($date);
            echo "Daily report generated: \\\\{$result['html_file']\\\\}\n";
            break;

        case 'weekly':
            $result = $reports->generateWeeklyReport($date);
            echo "Weekly report generated: \\\\{$result['html_file']\\\\}\n";
            break;

        default:
            echo "Usage: php automated_reports.php [daily|weekly] [date]\n";
    \\\\}
\\\\}
?>

Automation Scripts

Comprehensive Monitoring Script

#!/bin/bash
# Comprehensive Squert monitoring and maintenance

# Configuration
SQUERT_DIR="/var/www/squert"
LOG_DIR="/var/log/squert"
BACKUP_DIR="/var/backups/squert"
CONFIG_FILE="/var/www/squert/.scripts/squert.inc"
APACHE_LOG="/var/log/apache2/squert_error.log"

# Database configuration
DB_HOST="localhost"
DB_USER="squert"
DB_PASS="squertpassword"
DB_NAME="sguildb"

# Monitoring thresholds
MAX_LOG_SIZE="100M"
MAX_DISK_USAGE="90"
MAX_RESPONSE_TIME="5"

# Create necessary directories
mkdir -p "$LOG_DIR" "$BACKUP_DIR"

# Logging function
log_message() \\\\{
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"|tee -a "$LOG_DIR/monitor.log"
\\\\}

# Check Squert web interface availability
check_web_interface() \\\\{
    log_message "Checking Squert web interface..."

    local response_time
    response_time=$(curl -o /dev/null -s -w '%\\\\{time_total\\\\}' http://localhost/squert/ 2>/dev/null)

    if [ $? -eq 0 ]; then
        log_message "Web interface is accessible (response time: $\\\\{response_time\\\\}s)"

        # Check if response time is acceptable
        if (( $(echo "$response_time > $MAX_RESPONSE_TIME"|bc -l) )); then
            log_message "WARNING: Slow response time: $\\\\{response_time\\\\}s (threshold: $\\\\{MAX_RESPONSE_TIME\\\\}s)"
            return 1
        fi

        return 0
    else
        log_message "ERROR: Web interface is not accessible"
        return 1
    fi
\\\\}

# Check database connectivity
check_database() \\\\{
    log_message "Checking database connectivity..."

    mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1;" >/dev/null 2>&1

    if [ $? -eq 0 ]; then
        log_message "Database connection successful"

        # Check recent events
        local recent_events
        recent_events=$(mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" -N -e "
            SELECT COUNT(*) FROM event WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 1 HOUR);
        " 2>/dev/null)

        log_message "Recent events (last hour): $recent_events"
        return 0
    else
        log_message "ERROR: Database connection failed"
        return 1
    fi
\\\\}

# Check Apache service
check_apache() \\\\{
    log_message "Checking Apache service..."

    if systemctl is-active --quiet apache2; then
        log_message "Apache service is running"

        # Check for recent errors
        local error_count
        error_count=$(tail -n 100 "$APACHE_LOG" 2>/dev/null|grep -c "$(date '+%Y-%m-%d')"||echo "0")

        if [ "$error_count" -gt 10 ]; then
            log_message "WARNING: High number of Apache errors today: $error_count"
        fi

        return 0
    else
        log_message "ERROR: Apache service is not running"
        return 1
    fi
\\\\}

# Check disk space
check_disk_space() \\\\{
    log_message "Checking disk space..."

    local usage
    usage=$(df -h "$SQUERT_DIR"|awk 'NR==2 \\\\{print $5\\\\}'|sed 's/%//')

    log_message "Disk usage: $\\\\{usage\\\\}%"

    if [ "$usage" -gt "$MAX_DISK_USAGE" ]; then
        log_message "WARNING: High disk usage: $\\\\{usage\\\\}% (threshold: $\\\\{MAX_DISK_USAGE\\\\}%)"
        return 1
    fi

    return 0
\\\\}

# Check log file sizes
check_log_sizes() \\\\{
    log_message "Checking log file sizes..."

    find "$LOG_DIR" -name "*.log" -size +"$MAX_LOG_SIZE"|while read -r logfile; do
        log_message "WARNING: Large log file: $logfile"

        # Rotate large log files
        if [ -f "$logfile" ]; then
            mv "$logfile" "$\\\\{logfile\\\\}.$(date +%Y%m%d-%H%M%S)"
            touch "$logfile"
            chown www-data:www-data "$logfile"
            log_message "Rotated log file: $logfile"
        fi
    done
\\\\}

# Performance optimization
optimize_performance() \\\\{
    log_message "Running performance optimization..."

    # Clear PHP opcache if available
    if command -v php >/dev/null 2>&1; then
        php -r "if (function_exists('opcache_reset')) \\\\{ opcache_reset(); echo 'OPcache cleared\n'; \\\\}"
    fi

    # Optimize database tables
    mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "
        OPTIMIZE TABLE event;
        ANALYZE TABLE event;
    " >/dev/null 2>&1

    log_message "Performance optimization completed"
\\\\}

# Backup configuration
backup_configuration() \\\\{
    log_message "Backing up Squert configuration..."

    local backup_file="$BACKUP_DIR/squert-config-$(date +%Y%m%d-%H%M%S).tar.gz"

    tar -czf "$backup_file" \
        "$CONFIG_FILE" \
        "$SQUERT_DIR/.scripts/" \
        "/etc/apache2/sites-available/squert.conf" \
        2>/dev/null

    if [ $? -eq 0 ]; then
        log_message "Configuration backup created: $backup_file"

        # Keep only last 7 days of backups
        find "$BACKUP_DIR" -name "squert-config-*.tar.gz" -mtime +7 -delete

        return 0
    else
        log_message "ERROR: Configuration backup failed"
        return 1
    fi
\\\\}

# Generate health report
generate_health_report() \\\\{
    log_message "Generating health report..."

    local report_file="$LOG_DIR/health-report-$(date +%Y%m%d-%H%M%S).html"

    cat > "$report_file" << EOF
<!DOCTYPE html>
<html>
<head>
    <title>Squert Health Report</title>
    <style>
        body \\\\{ font-family: Arial, sans-serif; margin: 20px; \\\\}
        .status-ok \\\\{ color: green; \\\\}
        .status-warning \\\\{ color: orange; \\\\}
        .status-error \\\\{ color: red; \\\\}
        table \\\\{ border-collapse: collapse; width: 100%; \\\\}
        th, td \\\\{ border: 1px solid #ddd; padding: 8px; text-align: left; \\\\}
        th \\\\{ background-color: #f2f2f2; \\\\}
    </style>
</head>
<body>
    <h1>Squert Health Report</h1>
    <p>Generated: $(date)</p>

    <h2>System Status</h2>
    <table>
        <tr><th>Component</th><th>Status</th><th>Details</th></tr>
EOF

    # Check each component and add to report
    if check_web_interface >/dev/null 2>&1; then
        echo "        <tr><td>Web Interface</td><td class=\"status-ok\">OK</td><td>Accessible</td></tr>" >> "$report_file"
    else
        echo "        <tr><td>Web Interface</td><td class=\"status-error\">ERROR</td><td>Not accessible</td></tr>" >> "$report_file"
    fi

    if check_database >/dev/null 2>&1; then
        echo "        <tr><td>Database</td><td class=\"status-ok\">OK</td><td>Connected</td></tr>" >> "$report_file"
    else
        echo "        <tr><td>Database</td><td class=\"status-error\">ERROR</td><td>Connection failed</td></tr>" >> "$report_file"
    fi

    if check_apache >/dev/null 2>&1; then
        echo "        <tr><td>Apache</td><td class=\"status-ok\">OK</td><td>Running</td></tr>" >> "$report_file"
    else
        echo "        <tr><td>Apache</td><td class=\"status-error\">ERROR</td><td>Not running</td></tr>" >> "$report_file"
    fi

    local disk_usage
    disk_usage=$(df -h "$SQUERT_DIR"|awk 'NR==2 \\\\{print $5\\\\}')
    echo "        <tr><td>Disk Space</td><td class=\"status-ok\">OK</td><td>Usage: $disk_usage</td></tr>" >> "$report_file"

    cat >> "$report_file" << EOF
    </table>

    <h2>Recent Activity</h2>
    <pre>$(tail -n 20 "$LOG_DIR/monitor.log" 2>/dev/null||echo "No recent activity logged")</pre>
</body>
</html>
EOF

    log_message "Health report generated: $report_file"
\\\\}

# Send alert notification
send_alert() \\\\{
    local subject="$1"
    local message="$2"

    # Send email if mail is configured
    if command -v mail >/dev/null 2>&1; then
        echo "$message"|mail -s "Squert Alert: $subject" security@company.com
    fi

    # Log to syslog
    logger -t squert-monitor "$subject: $message"

    log_message "Alert sent: $subject"
\\\\}

# Main monitoring function
run_monitoring() \\\\{
    log_message "Starting Squert monitoring cycle"

    local issues=0

    # Run all checks
    check_web_interface||((issues++))
    check_database||((issues++))
    check_apache||((issues++))
    check_disk_space||((issues++))
    check_log_sizes

    # Performance optimization (weekly)
    if [ "$(date +%u)" -eq 1 ] && [ "$(date +%H)" -eq 2 ]; then
        optimize_performance
        backup_configuration
    fi

    # Generate health report (daily)
    if [ "$(date +%H)" -eq 6 ]; then
        generate_health_report
    fi

    # Send alerts if issues found
    if [ "$issues" -gt 0 ]; then
        send_alert "System Issues Detected" "Found $issues issues during monitoring. Check logs for details."
    fi

    log_message "Monitoring cycle completed with $issues issues"
    return $issues
\\\\}

# Maintenance functions
cleanup_old_files() \\\\{
    log_message "Cleaning up old files..."

    # Remove old log files (older than 30 days)
    find "$LOG_DIR" -name "*.log.*" -mtime +30 -delete

    # Remove old health reports (older than 7 days)
    find "$LOG_DIR" -name "health-report-*.html" -mtime +7 -delete

    # Remove old backups (older than 30 days)
    find "$BACKUP_DIR" -name "*.tar.gz" -mtime +30 -delete

    log_message "Cleanup completed"
\\\\}

# Update Squert
update_squert() \\\\{
    log_message "Checking for Squert updates..."

    cd "$SQUERT_DIR"||exit 1

    # Backup current version
    backup_configuration

    # Check for updates
    git fetch origin

    local current_commit
    local latest_commit
    current_commit=$(git rev-parse HEAD)
    latest_commit=$(git rev-parse origin/master)

    if [ "$current_commit" != "$latest_commit" ]; then
        log_message "Updates available, updating Squert..."

        # Pull updates
        git pull origin master

        # Set proper permissions
        chown -R www-data:www-data "$SQUERT_DIR"
        find "$SQUERT_DIR" -type f -exec chmod 644 \\\\{\\\\} \;
        find "$SQUERT_DIR" -type d -exec chmod 755 \\\\{\\\\} \;

        # Restart Apache
        systemctl restart apache2

        log_message "Squert updated successfully"
    else
        log_message "Squert is up to date"
    fi
\\\\}

# Command line interface
case "$\\\\{1:-monitor\\\\}" in
    "monitor")
        run_monitoring
        ;;
    "cleanup")
        cleanup_old_files
        ;;
    "update")
        update_squert
        ;;
    "backup")
        backup_configuration
        ;;
    "report")
        generate_health_report
        ;;
    "optimize")
        optimize_performance
        ;;
    *)
        echo "Usage: $0 \\\\{monitor|cleanup|update|backup|report|optimize\\\\}"
        echo ""
        echo "Commands:"
        echo "  monitor  - Run complete monitoring cycle (default)"
        echo "  cleanup  - Clean up old files and logs"
        echo "  update   - Check for and apply Squert updates"
        echo "  backup   - Backup Squert configuration"
        echo "  report   - Generate health report"
        echo "  optimize - Run performance optimization"
        exit 1
        ;;
esac

Integración Ejemplos

SIEM Integration

#!/usr/bin/env python3
# Squert SIEM integration script

import mysql.connector
import json
import requests
import time
from datetime import datetime, timedelta

class SquertSIEMIntegration:
    def __init__(self, config):
        self.config = config
        self.db_config = config['database']
        self.siem_config = config['siem']

    def connect_database(self):
        """Connect to Squert/Sguil database"""
        return mysql.connector.connect(**self.db_config)

    def get_recent_events(self, minutes=5):
        """Get events from the last N minutes"""
        connection = self.connect_database()
        cursor = connection.cursor(dictionary=True)

        query = """
            SELECT
                sid, cid, timestamp, src_ip, src_port, dst_ip, dst_port,
                ip_proto, signature, signature_gen, signature_id, signature_rev
            FROM event
            WHERE timestamp >= DATE_SUB(NOW(), INTERVAL %s MINUTE)
            ORDER BY timestamp DESC
        """

        cursor.execute(query, (minutes,))
        events = cursor.fetchall()

        cursor.close()
        connection.close()

        return events

    def transform_for_splunk(self, events):
        """Transform events for Splunk HEC"""
        splunk_events = []

        for event in events:
            splunk_event = \\\\{
                "time": int(event['timestamp'].timestamp()),
                "source": "squert",
                "sourcetype": "sguil:event",
                "index": self.siem_config.get('splunk_index', 'security'),
                "event": \\\\{
                    "sid": event['sid'],
                    "cid": event['cid'],
                    "timestamp": event['timestamp'].isoformat(),
                    "src_ip": event['src_ip'],
                    "src_port": event['src_port'],
                    "dst_ip": event['dst_ip'],
                    "dst_port": event['dst_port'],
                    "protocol": event['ip_proto'],
                    "signature": event['signature'],
                    "signature_id": event['signature_id'],
                    "signature_gen": event['signature_gen'],
                    "signature_rev": event['signature_rev']
                \\\\}
            \\\\}
            splunk_events.append(splunk_event)

        return splunk_events

    def send_to_splunk(self, events):
        """Send events to Splunk via HEC"""
        if not events:
            return True

        splunk_events = self.transform_for_splunk(events)

        headers = \\\\{
            'Authorization': f"Splunk \\\\{self.siem_config['splunk_token']\\\\}",
            'Content-Type': 'application/json'
        \\\\}

        for event in splunk_events:
            try:
                response = requests.post(
                    self.siem_config['splunk_hec_url'],
                    headers=headers,
                    json=event,
                    verify=False,
                    timeout=10
                )

                if response.status_code != 200:
                    print(f"Failed to send event to Splunk: \\\\{response.status_code\\\\}")
                    return False

            except Exception as e:
                print(f"Error sending to Splunk: \\\\{e\\\\}")
                return False

        print(f"Sent \\\\{len(splunk_events)\\\\} events to Splunk")
        return True

    def transform_for_elasticsearch(self, events):
        """Transform events for Elasticsearch"""
        es_events = []

        for event in events:
            es_event = \\\\{
                "@timestamp": event['timestamp'].isoformat(),
                "source": \\\\{
                    "ip": event['src_ip'],
                    "port": event['src_port']
                \\\\},
                "destination": \\\\{
                    "ip": event['dst_ip'],
                    "port": event['dst_port']
                \\\\},
                "network": \\\\{
                    "protocol": self.get_protocol_name(event['ip_proto'])
                \\\\},
                "event": \\\\{
                    "id": f"\\\\{event['sid']\\\\}-\\\\{event['cid']\\\\}",
                    "category": "network",
                    "type": "alert",
                    "severity": self.get_severity(event['signature_id'])
                \\\\},
                "rule": \\\\{
                    "id": event['signature_id'],
                    "name": event['signature'],
                    "version": event['signature_rev']
                \\\\},
                "sguil": \\\\{
                    "sid": event['sid'],
                    "cid": event['cid'],
                    "signature_gen": event['signature_gen']
                \\\\}
            \\\\}
            es_events.append(es_event)

        return es_events

    def send_to_elasticsearch(self, events):
        """Send events to Elasticsearch"""
        if not events:
            return True

        es_events = self.transform_for_elasticsearch(events)

        for event in es_events:
            try:
                index_name = f"squert-\\\\{datetime.now().strftime('%Y.%m.%d')\\\\}"
                doc_id = event['event']['id']

                response = requests.post(
                    f"\\\\{self.siem_config['elasticsearch_url']\\\\}/\\\\{index_name\\\\}/_doc/\\\\{doc_id\\\\}",
                    json=event,
                    timeout=10
                )

                if response.status_code not in [200, 201]:
                    print(f"Failed to send event to Elasticsearch: \\\\{response.status_code\\\\}")
                    return False

            except Exception as e:
                print(f"Error sending to Elasticsearch: \\\\{e\\\\}")
                return False

        print(f"Sent \\\\{len(es_events)\\\\} events to Elasticsearch")
        return True

    def get_protocol_name(self, proto_num):
        """Convert protocol number to name"""
        protocols = \\\\{1: 'icmp', 6: 'tcp', 17: 'udp'\\\\}
        return protocols.get(proto_num, str(proto_num))

    def get_severity(self, signature_id):
        """Determine event severity based on signature ID"""
        if signature_id in [1, 2, 3]:
            return 'high'
        elif signature_id in [4, 5, 6]:
            return 'medium'
        else:
            return 'low'

    def run_integration(self):
        """Run the SIEM integration"""
        print(f"Starting SIEM integration at \\\\{datetime.now()\\\\}")

        # Get recent events
        events = self.get_recent_events(5)  # Last 5 minutes

        if not events:
            print("No new events to process")
            return

        print(f"Processing \\\\{len(events)\\\\} events")

        # Send to configured SIEM systems
        if self.siem_config.get('splunk_enabled', False):
            self.send_to_splunk(events)

        if self.siem_config.get('elasticsearch_enabled', False):
            self.send_to_elasticsearch(events)

        print("SIEM integration completed")

# Configuration
config = \\\\{
    'database': \\\\{
        'host': 'localhost',
        'user': 'squert',
        'password': 'squertpassword',
        'database': 'sguildb'
    \\\\},
    'siem': \\\\{
        'splunk_enabled': True,
        'splunk_hec_url': 'https://splunk.company.com:8088/services/collector/event',
        'splunk_token': 'your-hec-token',
        'splunk_index': 'security',

        'elasticsearch_enabled': True,
        'elasticsearch_url': 'http://elasticsearch.company.com:9200'
    \\\\}
\\\\}

# Run integration
if __name__ == "__main__":
    integration = SquertSIEMIntegration(config)
    integration.run_integration()

Troubleshooting

Common Issues

Interfaz web No Carga:

# Check Apache status
sudo systemctl status apache2

# Check Apache error logs
sudo tail -f /var/log/apache2/squert_error.log

# Check PHP errors
sudo tail -f /var/log/apache2/error.log|grep -i php

# Verify file permissions
sudo chown -R www-data:www-data /var/www/squert
sudo chmod -R 755 /var/www/squert

# Test PHP configuration
php -m|grep -i mysql
php -r "phpinfo();"|grep -i mysql

** Problemas de conexión de datos:**

# Test database connection
mysql -h localhost -u squert -p sguildb -e "SELECT COUNT(*) FROM event;"

# Check database permissions
mysql -u root -p -e "SHOW GRANTS FOR 'squert'@'localhost';"

# Verify database configuration
cat /var/www/squert/.scripts/squert.inc|grep -E "(dbhost|dbuser|dbpass|dbname)"

# Check MySQL service
sudo systemctl status mysql
sudo systemctl start mysql

** Cuestiones de desempeño**

# Check system resources
top -p $(pgrep apache2)
free -h
df -h

# Optimize database
mysql -u squert -p sguildb -e "OPTIMIZE TABLE event;"
mysql -u squert -p sguildb -e "ANALYZE TABLE event;"

# Check slow queries
mysql -u root -p -e "SHOW PROCESSLIST;"

# Enable PHP OPcache
echo "opcache.enable=1" >> /etc/php/7.4/apache2/php.ini
sudo systemctl restart apache2

Performance Optimization

Optimización del rendimiento de Squert:

# Apache optimization
cat >> /etc/apache2/conf-available/squert-performance.conf << 'EOF'
# Squert performance optimizations

# Enable compression
LoadModule deflate_module modules/mod_deflate.so
<Location "/squert">
    SetOutputFilter DEFLATE
    SetEnvIfNoCase Request_URI \
        \.(?:gif|jpe?g|png)$ no-gzip dont-vary
    SetEnvIfNoCase Request_URI \
        \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
</Location>

# Enable caching
LoadModule expires_module modules/mod_expires.so
<Location "/squert">
    ExpiresActive On
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    ExpiresByType image/png "access plus 1 month"
    ExpiresByType image/jpg "access plus 1 month"
    ExpiresByType image/jpeg "access plus 1 month"
    ExpiresByType image/gif "access plus 1 month"
</Location>
EOF

sudo a2enconf squert-performance
sudo systemctl restart apache2

# PHP optimization
cat >> /etc/php/7.4/apache2/conf.d/99-squert.ini << 'EOF'
; Squert PHP optimizations
memory_limit = 256M
max_execution_time = 60
max_input_vars = 3000

; OPcache settings
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 4000
opcache.revalidate_freq = 2
opcache.fast_shutdown = 1
EOF

sudo systemctl restart apache2

# Database optimization
mysql -u root -p << 'EOF'
-- Optimize Sguil database for Squert
USE sguildb;

-- Add indexes for common Squert queries
CREATE INDEX idx_event_timestamp_src ON event (timestamp, src_ip);
CREATE INDEX idx_event_timestamp_dst ON event (timestamp, dst_ip);
CREATE INDEX idx_event_signature_timestamp ON event (signature_id, timestamp);
CREATE INDEX idx_event_src_dst ON event (src_ip, dst_ip);

-- Optimize table
OPTIMIZE TABLE event;
ANALYZE TABLE event;
EOF

Security Considerations

Access Control

** Seguridad de la Interfaz en Internet** - Implementar HTTPS para todo acceso Squert - Use mecanismos de autenticación fuertes - Ejecutar el tiempo y la gestión del período de sesiones - Actualizaciones periódicas de seguridad para todos los componentes - Supervisar los registros de acceso para actividades sospechosas

Seguridad de la base de datos** - Usar un usuario de base de datos dedicado con privilegios mínimos - Implementar el cifrado de conexión de bases de datos - Actualizaciones periódicas de seguridad de bases de datos - Monitorear registros de acceso a bases de datos - Implementar el cifrado de respaldo

Protección de datos

Event Data Security: - Cifrar datos de eventos sensibles en reposo - Implementar políticas de retención de datos - Acceso seguro a los datos de captura de paquetes - Limpieza regular de archivos temporales - Implementar registros de acceso para datos de eventos

** Seguridad Operacional** - Evaluaciones periódicas de seguridad de la infraestructura de Squert - Vigilancia de los intentos de acceso no autorizado - Implementar procedimientos adecuados de respaldo y recuperación - Actualizaciones periódicas de Squert y dependencias - Procedimientos de respuesta a incidentes de compromiso Squert

Referencias

  1. [Squert GitHub Repository](URL_22__
  2. [Sguil Official Documentation](URL_23_
  3. Apache HTTP Server Documentation_
  4. [PHP Security Best Practices](URL_25_
  5. MySQL Performance Tuning_