addDefaultFormTab($tabs); $this->addStandardTab('Log', $tabs, $options); return $tabs; } /** * Display the CVE Rule form * * @param integer $ID ID of the item * @param array $options * @return boolean */ function showForm($ID, $options = []) { global $CFG_GLPI; $this->initForm($ID, $options); $this->showFormHeader($options); $canedit = $this->can($ID, UPDATE); echo ""; // Rule Name echo "" . __('Rule Name', 'cve') . ""; echo ""; echo Html::input('name', ['value' => $this->fields['name'], 'size' => 40]); echo ""; // Priority echo "" . __('Priority', 'cve') . ""; echo ""; echo Html::input('priority', ['value' => $this->fields['priority'], 'size' => 5, 'type' => 'number', 'min' => 1]); echo "
" . __('Lower numbers are processed first', 'cve') . ""; echo ""; echo ""; echo ""; // Criteria - Severity echo "" . __('Severity', 'cve') . ""; echo ""; $criteria = json_decode($this->fields['criteria'], true) ?: []; $severity = $criteria['severity'] ?? 'CRITICAL'; $severity_options = [ 'CRITICAL' => __('Critical', 'cve'), 'HIGH' => __('High', 'cve'), 'MEDIUM' => __('Medium', 'cve'), 'LOW' => __('Low', 'cve') ]; Dropdown::showFromArray('criteria_severity', $severity_options, ['value' => $severity]); echo ""; // Status echo "" . __('Status', 'cve') . ""; echo ""; $status_options = [ 'NEW' => __('New', 'cve'), 'ANALYZED' => __('Analyzed', 'cve'), 'ASSIGNED' => __('Assigned', 'cve'), 'RESOLVED' => __('Resolved', 'cve') ]; Dropdown::showFromArray('rule_status', $status_options, ['value' => $this->fields['status'] ?? 'NEW']); echo ""; echo ""; echo ""; // Actions - Create Ticket echo "" . __('Create Ticket', 'cve') . ""; echo ""; $actions = json_decode($this->fields['actions'], true) ?: []; $create_ticket = isset($actions['create_ticket']) ? $actions['create_ticket'] : true; Dropdown::showYesNo('actions_create_ticket', $create_ticket); echo ""; // Ticket Priority echo "" . __('Ticket Priority', 'cve') . ""; echo ""; $ticket_priority = $actions['ticket_priority'] ?? 'NORMAL'; $priority_options = [ 'VERY HIGH' => __('Very High', 'cve'), 'HIGH' => __('High', 'cve'), 'NORMAL' => __('Normal', 'cve'), 'LOW' => __('Low', 'cve') ]; Dropdown::showFromArray('actions_ticket_priority', $priority_options, ['value' => $ticket_priority]); echo ""; echo ""; echo ""; // Actions - Notify Admins echo "" . __('Notify Administrators', 'cve') . ""; echo ""; $notify_admins = isset($actions['notify_admins']) ? $actions['notify_admins'] : false; Dropdown::showYesNo('actions_notify_admins', $notify_admins); echo ""; // Actions - Add to Report echo "" . __('Add to Vulnerability Report', 'cve') . ""; echo ""; $add_to_report = isset($actions['add_to_report']) ? $actions['add_to_report'] : false; Dropdown::showYesNo('actions_add_to_report', $add_to_report); echo ""; echo ""; echo ""; // Is Active echo "" . __('Active Rule', 'cve') . ""; echo ""; Dropdown::showYesNo('is_active', $this->fields['is_active']); echo ""; echo ""; echo ""; $this->showFormButtons($options); return true; } /** * Process a CVE with rules * * @param PluginCveCve $cve CVE to process * @return boolean True if any rule was applied */ static function processCVE(PluginCveCve $cve) { $rule = new self(); // Get active rules sorted by priority $rules = $rule->find(['is_active' => 1], ['priority' => 'ASC']); $rule_applied = false; foreach ($rules as $rule_data) { // Load the rule $rule->getFromDB($rule_data['id']); // Check if the CVE matches the criteria if (self::matchesCriteria($cve, $rule_data)) { // Apply the actions self::applyActions($cve, $rule_data); $rule_applied = true; } } return $rule_applied; } /** * Check if a CVE matches rule criteria * * @param PluginCveCve $cve CVE to check * @param array $rule_data Rule data * @return boolean True if the CVE matches the criteria */ private static function matchesCriteria(PluginCveCve $cve, array $rule_data) { $criteria = json_decode($rule_data['criteria'], true) ?: []; // Check severity if (isset($criteria['severity'])) { // Get the numeric values for comparison $severity_values = [ 'CRITICAL' => 4, 'HIGH' => 3, 'MEDIUM' => 2, 'LOW' => 1 ]; $rule_severity = $severity_values[$criteria['severity']] ?? 0; $cve_severity = $severity_values[$cve->fields['severity']] ?? 0; // Match if CVE severity is greater than or equal to rule severity if ($cve_severity < $rule_severity) { return false; } } // Check affected products if specified if (isset($criteria['affected_products']) && !empty($criteria['affected_products'])) { $cve_products = json_decode($cve->fields['affected_products'], true) ?: []; $rule_products = $criteria['affected_products']; $found = false; foreach ($rule_products as $product) { if (in_array($product, $cve_products)) { $found = true; break; } } if (!$found) { return false; } } // Check CVSS score range if specified if (isset($criteria['cvss_min']) && $cve->fields['cvss_score'] < $criteria['cvss_min']) { return false; } if (isset($criteria['cvss_max']) && $cve->fields['cvss_score'] > $criteria['cvss_max']) { return false; } // All criteria matched or no criteria specified return true; } /** * Apply rule actions to a CVE * * @param PluginCveCve $cve CVE to process * @param array $rule_data Rule data * @return boolean True if actions were applied successfully */ private static function applyActions(PluginCveCve $cve, array $rule_data) { $actions = json_decode($rule_data['actions'], true) ?: []; // Create a ticket if needed if (isset($actions['create_ticket']) && $actions['create_ticket']) { $ticket_options = []; // Set ticket priority if (isset($actions['ticket_priority'])) { switch ($actions['ticket_priority']) { case 'VERY HIGH': $ticket_options['priority'] = 5; break; case 'HIGH': $ticket_options['priority'] = 4; break; case 'NORMAL': $ticket_options['priority'] = 3; break; case 'LOW': $ticket_options['priority'] = 2; break; default: $ticket_options['priority'] = 3; // Default to normal } } // Create the ticket $cve->createTicket($cve->getID(), $ticket_options); } // Send notifications if needed if (isset($actions['notify_admins']) && $actions['notify_admins']) { // This would implement the notification logic // For example: NotificationEvent::raiseEvent('new_cve', $cve); } // Add to report if needed if (isset($actions['add_to_report']) && $actions['add_to_report']) { // This would implement the reporting logic } return true; } /** * Get search function for the class * * @return array of search options */ function rawSearchOptions() { $tab = []; $tab[] = [ 'id' => 'common', 'name' => self::getTypeName(2) ]; $tab[] = [ 'id' => '1', 'table' => $this->getTable(), 'field' => 'name', 'name' => __('Rule Name', 'cve'), 'datatype' => 'itemlink', 'massiveaction' => false ]; $tab[] = [ 'id' => '2', 'table' => $this->getTable(), 'field' => 'priority', 'name' => __('Priority', 'cve'), 'datatype' => 'number', 'min' => 1, 'massiveaction' => true ]; $tab[] = [ 'id' => '3', 'table' => $this->getTable(), 'field' => 'criteria', 'name' => __('Criteria', 'cve'), 'datatype' => 'text', 'massiveaction' => false ]; $tab[] = [ 'id' => '4', 'table' => $this->getTable(), 'field' => 'actions', 'name' => __('Actions', 'cve'), 'datatype' => 'text', 'massiveaction' => false ]; $tab[] = [ 'id' => '5', 'table' => $this->getTable(), 'field' => 'is_active', 'name' => __('Active', 'cve'), 'datatype' => 'bool', 'massiveaction' => true ]; $tab[] = [ 'id' => '19', 'table' => $this->getTable(), 'field' => 'date_mod', 'name' => __('Last update', 'cve'), 'datatype' => 'datetime', 'massiveaction' => false ]; $tab[] = [ 'id' => '16', 'table' => $this->getTable(), 'field' => 'date_creation', 'name' => __('Creation date', 'cve'), 'datatype' => 'datetime', 'massiveaction' => false ]; return $tab; } /** * Install the plugin database schema * * @return boolean */ static function install(Migration $migration) { global $DB; $table = self::getTable(); if (!$DB->tableExists($table)) { $migration->displayMessage("Installing $table"); $query = "CREATE TABLE IF NOT EXISTS `$table` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `criteria` json DEFAULT NULL, `actions` json DEFAULT NULL, `priority` int(11) NOT NULL DEFAULT '1', `is_active` tinyint(1) NOT NULL DEFAULT '0', `status` varchar(20) DEFAULT 'NEW', `date_creation` datetime DEFAULT NULL, `date_mod` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `name` (`name`), KEY `is_active` (`is_active`), KEY `priority` (`priority`), KEY `date_creation` (`date_creation`), KEY `date_mod` (`date_mod`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci"; $DB->query($query) or die("Error creating $table " . $DB->error()); // Add default rules $default_rules = [ [ 'name' => 'Critical Vulnerabilities - Immediate Ticket', 'criteria' => json_encode(['severity' => 'CRITICAL']), 'actions' => json_encode([ 'create_ticket' => true, 'ticket_priority' => 'VERY HIGH', 'notify_admins' => true ]), 'priority' => 1, 'is_active' => 1, 'status' => 'NEW', 'date_creation' => $_SESSION['glpi_currenttime'], 'date_mod' => $_SESSION['glpi_currenttime'] ], [ 'name' => 'High Risk Vulnerabilities - Create Ticket', 'criteria' => json_encode(['severity' => 'HIGH']), 'actions' => json_encode([ 'create_ticket' => true, 'ticket_priority' => 'HIGH', 'notify_admins' => false ]), 'priority' => 2, 'is_active' => 1, 'status' => 'NEW', 'date_creation' => $_SESSION['glpi_currenttime'], 'date_mod' => $_SESSION['glpi_currenttime'] ], [ 'name' => 'Medium Risk - Add to Report', 'criteria' => json_encode(['severity' => 'MEDIUM']), 'actions' => json_encode([ 'create_ticket' => false, 'add_to_report' => true ]), 'priority' => 3, 'is_active' => 1, 'status' => 'NEW', 'date_creation' => $_SESSION['glpi_currenttime'], 'date_mod' => $_SESSION['glpi_currenttime'] ] ]; $rule = new self(); foreach ($default_rules as $rule_data) { $rule->add($rule_data); } } return true; } /** * Uninstall the plugin database schema * * @return boolean */ static function uninstall(Migration $migration) { global $DB; $table = self::getTable(); if ($DB->tableExists($table)) { $migration->displayMessage("Uninstalling $table"); $migration->dropTable($table); } return true; } }