Merge pull request #8608 from JakubOnderka/nids-cleanup

Nids cleanup
pull/8625/head
Jakub Onderka 2022-09-22 17:28:32 +02:00 committed by GitHub
commit 4d1dc9a617
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 21 additions and 383 deletions

View File

@ -49,14 +49,6 @@ class AppController extends Controller
public $restResponsePayload = null;
// Used for _isAutomation(), a check that returns true if the controller & action combo matches an action that is a non-xml and non-json automation method
// This is used to allow authentication via headers for methods not covered by _isRest() - as that only checks for JSON and XML formats
public $automationArray = array(
'events' => array('csv', 'nids', 'hids', 'xml', 'restSearch', 'stix', 'updateGraph', 'downloadOpenIOCEvent'),
'attributes' => array('text', 'downloadAttachment', 'returnAttributes', 'restSearch', 'rpz', 'bro'),
'objects' => array('restSearch')
);
protected $_legacyParams = array();
/** @var array */
public $userRole;

View File

@ -10,6 +10,14 @@ class IndexFilterComponent extends Component
public $Controller;
public $isRest = null;
// Used for isApiFunction(), a check that returns true if the controller & action combo matches an action that is a non-xml and non-json automation method
// This is used to allow authentication via headers for methods not covered by _isRest() - as that only checks for JSON and XML formats
const AUTOMATION_ARRAY = array(
'events' => array('csv', 'nids', 'hids', 'xml', 'restSearch', 'stix', 'updateGraph', 'downloadOpenIOCEvent'),
'attributes' => array('text', 'downloadAttachment', 'returnAttributes', 'restSearch', 'rpz', 'bro'),
'objects' => array('restSearch'),
);
public function initialize(Controller $controller)
{
$this->Controller = $controller;
@ -121,6 +129,6 @@ class IndexFilterComponent extends Component
*/
public function isApiFunction($controller, $action)
{
return isset($this->Controller->automationArray[$controller]) && in_array($action, $this->Controller->automationArray[$controller], true);
return isset(self::AUTOMATION_ARRAY[$controller]) && in_array($action, self::AUTOMATION_ARRAY[$controller], true);
}
}

View File

@ -1,6 +1,6 @@
<?php
class NidsExport
abstract class NidsExport
{
public $rules = array();
@ -858,15 +858,16 @@ class NidsExport
}
}
/**
* @param array $attribute
* @return array|string[]
*/
public static function getIpPort($attribute)
{
$ipport = array();
if (strpos($attribute['type'], 'port') !== false) {
$ipport = explode('|', $attribute['value']);
return explode('|', $attribute['value']);
} else {
$ipport[0] = $attribute['value'];
$ipport[1] = 'any';
return [$attribute['value'], 'any'];
}
return $ipport;
}
}

View File

@ -2622,7 +2622,7 @@ class AppModel extends Model
return $remainingTime > 0 || $failThresholdReached;
}
public function getUpdateFailNumber()
private function getUpdateFailNumber()
{
$this->AdminSetting = ClassRegistry::init('AdminSetting');
$updateFailNumber = $this->AdminSetting->getSetting('update_fail_number');
@ -2635,7 +2635,7 @@ class AppModel extends Model
$this->AdminSetting->changeSetting('update_fail_number', 0);
}
public function __increaseUpdateFailNumber()
private function __increaseUpdateFailNumber()
{
$this->AdminSetting = ClassRegistry::init('AdminSetting');
$updateFailNumber = $this->AdminSetting->getSetting('update_fail_number');
@ -2737,7 +2737,7 @@ class AppModel extends Model
return true;
}
public function removeDuplicatedUUIDs()
private function removeDuplicatedUUIDs()
{
$removedResults = array(
'Event' => $this->removeDuplicateEventUUIDs(),
@ -2782,7 +2782,7 @@ class AppModel extends Model
return $counter;
}
public function removeDuplicateAttributeUUIDs()
private function removeDuplicateAttributeUUIDs()
{
$this->Attribute = ClassRegistry::init('Attribute');
$this->Log = ClassRegistry::init('Log');
@ -2836,7 +2836,7 @@ class AppModel extends Model
return $counter;
}
public function removeDuplicateEventUUIDs()
private function removeDuplicateEventUUIDs()
{
$this->Event = ClassRegistry::init('Event');
$this->Log = ClassRegistry::init('Log');

View File

@ -1024,163 +1024,6 @@ class Attribute extends AppModel
return $data;
}
public function hids($user, $type, $tags = '', $from = false, $to = false, $last = false, $jobId = false, $enforceWarninglist = false)
{
if (empty($user)) {
throw new MethodNotAllowedException(__('Could not read user.'));
}
// check if it's a valid type
if ($type != 'md5' && $type != 'sha1' && $type != 'sha256') {
throw new UnauthorizedException(__('Invalid hash type.'));
}
$conditions = array();
$typeArray = array($type, 'filename|' . $type);
if ($type == 'md5') {
$typeArray[] = 'malware-sample';
}
$rules = array();
$eventIds = $this->Event->fetchEventIds($user, [
'from' => $from,
'to' => $to,
'last' => $last
]);
if (!empty($tags)) {
$tag = ClassRegistry::init('Tag');
$args = $this->dissectArgs($tags);
$tagArray = $tag->fetchEventTagIds($args[0], $args[1]);
if (!empty($tagArray[0])) {
foreach ($eventIds as $k => $v) {
if (!in_array($v['Event']['id'], $tagArray[0])) {
unset($eventIds[$k]);
}
}
}
if (!empty($tagArray[1])) {
foreach ($eventIds as $k => $v) {
if (in_array($v['Event']['id'], $tagArray[1])) {
unset($eventIds[$k]);
}
}
}
}
App::uses('HidsExport', 'Export');
$continue = false;
$eventCount = count($eventIds);
if ($jobId) {
$this->Job = ClassRegistry::init('Job');
$this->Job->id = $jobId;
if (!$this->Job->exists()) {
$jobId = false;
}
}
foreach ($eventIds as $k => $event) {
$conditions['AND'] = array('Attribute.to_ids' => 1, 'Event.published' => 1, 'Attribute.type' => $typeArray, 'Attribute.event_id' => $event['Event']['id']);
$options = array(
'conditions' => $conditions,
'group' => array('Attribute.type', 'Attribute.value1'),
'enforceWarninglist' => $enforceWarninglist,
'flatten' => true
);
$items = $this->fetchAttributes($user, $options);
if (empty($items)) {
continue;
}
$export = new HidsExport();
$rules = array_merge($rules, $export->export($items, strtoupper($type), $continue));
$continue = true;
if ($jobId && ($k % 10 == 0)) {
$this->Job->saveField('progress', $k * 80 / $eventCount);
}
}
return $rules;
}
public function nids($user, $format, $id = false, $continue = false, $tags = false, $from = false, $to = false, $last = false, $type = false, $enforceWarninglist = false, $includeAllTags = false)
{
if (empty($user)) {
throw new MethodNotAllowedException(__('Could not read user.'));
}
$eventIds = $this->Event->fetchEventIds($user, [
'from' => $from,
'to' => $to,
'last' => $last
]);
// If we sent any tags along, load the associated tag names for each attribute
if ($tags) {
$tag = ClassRegistry::init('Tag');
$args = $this->dissectArgs($tags);
$tagArray = $tag->fetchEventTagIds($args[0], $args[1]);
if (!empty($tagArray[0])) {
foreach ($eventIds as $k => $v) {
if (!in_array($v['Event']['id'], $tagArray[0])) {
unset($eventIds[$k]);
}
}
}
if (!empty($tagArray[1])) {
foreach ($eventIds as $k => $v) {
if (in_array($v['Event']['id'], $tagArray[1])) {
unset($eventIds[$k]);
}
}
}
}
if ($id) {
foreach ($eventIds as $k => $v) {
if ($v['Event']['id'] !== $id) {
unset($eventIds[$k]);
}
}
}
if ($format == 'suricata') {
App::uses('NidsSuricataExport', 'Export');
} else {
App::uses('NidsSnortExport', 'Export');
}
$rules = array();
foreach ($eventIds as $event) {
$conditions['AND'] = array('Attribute.to_ids' => 1, "Event.published" => 1, 'Attribute.event_id' => $event['Event']['id']);
$valid_types = array('ip-dst', 'ip-src', 'ip-dst|port', 'ip-src|port', 'eppn', 'email', 'email-src', 'email-dst', 'email-subject', 'email-attachment', 'domain', 'domain|ip', 'hostname', 'url', 'user-agent', 'snort');
$conditions['AND']['Attribute.type'] = $valid_types;
if (!empty($type)) {
$conditions['AND'][] = array('Attribute.type' => $type);
}
$params = array(
'conditions' => $conditions, // array of conditions
'recursive' => -1, // int
'fields' => array('Attribute.id', 'Attribute.event_id', 'Attribute.type', 'Attribute.value'),
'contain' => array('Event'=> array('fields' => array('Event.id', 'Event.threat_level_id'))),
'group' => array('Attribute.type', 'Attribute.value1'), // fields to GROUP BY
'enforceWarninglist' => $enforceWarninglist,
'includeAllTags' => $includeAllTags,
'flatten' => true
);
$items = $this->fetchAttributes($user, $params);
if (empty($items)) {
continue;
}
// export depending on the requested type
switch ($format) {
case 'suricata':
$export = new NidsSuricataExport();
break;
case 'snort':
$export = new NidsSnortExport();
break;
}
$rules = array_merge($rules, $export->export($items, $user['nids_sid'], $format, $continue));
// Only prepend the comments once
$continue = true;
}
return $rules;
}
public function set_filter_tags(&$params, $conditions, $options)
{
if (empty($params['tags']) && empty($params['event_tags'])) {
@ -1315,212 +1158,6 @@ class Attribute extends AppModel
return $conditions;
}
public function text($user, $type, $tags = false, $eventId = false, $allowNonIDS = false, $from = false, $to = false, $last = false, $enforceWarninglist = false, $allowNotPublished = false)
{
//permissions are taken care of in fetchAttributes()
$conditions['AND'] = array();
if ($allowNonIDS === false) {
$conditions['AND']['Attribute.to_ids'] = 1;
if ($allowNotPublished === false) {
$conditions['AND']['Event.published'] = 1;
}
}
if (!is_array($type) && $type !== 'all') {
$conditions['AND']['Attribute.type'] = $type;
}
if ($from) {
$conditions['AND']['Event.date >='] = $from;
}
if ($to) {
$conditions['AND']['Event.date <='] = $to;
}
if ($last) {
$conditions['AND']['Event.publish_timestamp >='] = $last;
}
if ($eventId !== false) {
$conditions['AND'][] = array('Event.id' => $eventId);
} elseif ($tags !== false) {
$passed_param = array('tags' => $tags);
$conditions = $this->set_filter_tags($passed_param, $conditions, array('scope' => 'Attribute'));
}
$attributes = $this->fetchAttributes($user, array(
'conditions' => $conditions,
'order' => 'Attribute.value1 ASC',
'fields' => array('value'),
'contain' => array('Event' => array(
'fields' => array('Event.id', 'Event.published', 'Event.date', 'Event.publish_timestamp'),
)),
'enforceWarninglist' => $enforceWarninglist,
'flatten' => 1
));
return $attributes;
}
public function rpz($user, $tags = false, $eventId = false, $from = false, $to = false, $enforceWarninglist = false)
{
// we can group hostname and domain as well as ip-src and ip-dst in this case
$conditions['AND'] = array('Attribute.to_ids' => 1, 'Event.published' => 1);
$typesToFetch = array('ip' => array('ip-src', 'ip-dst'), 'domain' => array('domain'), 'hostname' => array('hostname'));
if ($from) {
$conditions['AND']['Event.date >='] = $from;
}
if ($to) {
$conditions['AND']['Event.date <='] = $to;
}
if ($eventId !== false) {
$conditions['AND'][] = array('Event.id' => $eventId);
}
if ($tags !== false) {
// If we sent any tags along, load the associated tag names for each attribute
$tag = ClassRegistry::init('Tag');
$args = $this->dissectArgs($tags);
$tagArray = $tag->fetchEventTagIds($args[0], $args[1]);
$temp = array();
foreach ($tagArray[0] as $accepted) {
$temp['OR'][] = array('Event.id' => $accepted);
}
$conditions['AND'][] = $temp;
$temp = array();
foreach ($tagArray[1] as $rejected) {
$temp['AND'][] = array('Event.id !=' => $rejected);
}
$conditions['AND'][] = $temp;
}
$values = array();
foreach ($typesToFetch as $k => $v) {
$tempConditions = $conditions;
$tempConditions['type'] = $v;
$temp = $this->fetchAttributes(
$user,
array(
'conditions' => $tempConditions,
'fields' => array('Attribute.value'), // array of field names
'enforceWarninglist' => $enforceWarninglist,
'flatten' => 1
)
);
if (empty($temp)) {
continue;
}
if ($k == 'hostname') {
foreach ($temp as $value) {
$found = false;
if (isset($values['domain'])) {
foreach ($values['domain'] as $domain) {
if (strpos($value['Attribute']['value'], $domain) != 0) {
$found = true;
}
}
}
if (!$found) {
$values[$k][] = $value['Attribute']['value'];
}
}
} else {
foreach ($temp as $value) {
$values[$k][] = $value['Attribute']['value'];
}
}
unset($temp);
}
return $values;
}
public function bro($user, $type, $tags = false, $eventId = false, $from = false, $to = false, $last = false, $enforceWarninglist = false, $skipHeader = false)
{
App::uses('BroExport', 'Export');
$export = new BroExport();
if ($type == 'all') {
$types = array_keys($export->mispTypes);
} else {
$types = array($type);
}
$intel = array();
foreach ($types as $type) {
//restricting to non-private or same org if the user is not a site-admin.
$conditions['AND'] = array('Attribute.to_ids' => 1, 'Event.published' => 1);
if ($from) {
$conditions['AND']['Event.date >='] = $from;
}
if ($to) {
$conditions['AND']['Event.date <='] = $to;
}
if ($last) {
$conditions['AND']['Event.publish_timestamp >='] = $last;
}
if ($eventId !== false) {
$temp = array();
$args = $this->dissectArgs($eventId);
foreach ($args[0] as $accepted) {
$temp['OR'][] = array('Event.id' => $accepted);
}
$conditions['AND'][] = $temp;
$temp = array();
foreach ($args[1] as $rejected) {
$temp['AND'][] = array('Event.id !=' => $rejected);
}
$conditions['AND'][] = $temp;
}
if ($tags !== false) {
// If we sent any tags along, load the associated tag names for each attribute
$tag = ClassRegistry::init('Tag');
$args = $this->dissectArgs($tags);
$tagArray = $tag->fetchEventTagIds($args[0], $args[1]);
$temp = array();
foreach ($tagArray[0] as $accepted) {
$temp['OR'][] = array('Event.id' => $accepted);
}
$conditions['AND'][] = $temp;
$temp = array();
foreach ($tagArray[1] as $rejected) {
$temp['AND'][] = array('Event.id !=' => $rejected);
}
$conditions['AND'][] = $temp;
}
$this->Allowedlist = ClassRegistry::init('Allowedlist');
$this->allowedlist = $this->Allowedlist->getBlockedValues();
$instanceString = 'MISP';
if (Configure::read('MISP.host_org_id') && Configure::read('MISP.host_org_id') > 0) {
$this->Event->Orgc->id = Configure::read('MISP.host_org_id');
if ($this->Event->Orgc->exists()) {
$instanceString = $this->Event->Orgc->field('name') . ' MISP';
}
}
$mispTypes = $export->getMispTypes($type);
foreach ($mispTypes as $mispType) {
$conditions['AND']['Attribute.type'] = $mispType[0];
$intel = array_merge($intel, $this->__bro($user, $conditions, $mispType[1], $export, $this->allowedlist, $instanceString, $enforceWarninglist));
}
}
natsort($intel);
$intel = array_unique($intel);
if (empty($skipHeader)) {
array_unshift($intel, $export->header);
}
return $intel;
}
private function __bro($user, $conditions, $valueField, $export, $allowedlist, $instanceString, $enforceWarninglist)
{
$attributes = $this->fetchAttributes(
$user,
array(
'conditions' => $conditions, // array of conditions
'order' => 'Attribute.value' . $valueField . ' ASC',
'recursive' => -1, // int
'fields' => array('Attribute.id', 'Attribute.event_id', 'Attribute.type', 'Attribute.category', 'Attribute.comment', 'Attribute.to_ids', 'Attribute.value', 'Attribute.value' . $valueField),
'contain' => array('Event' => array('fields' => array('Event.id', 'Event.threat_level_id', 'Event.orgc_id', 'Event.uuid'))),
'enforceWarninglist' => $enforceWarninglist,
'flatten' => 1
)
);
$orgs = $this->Event->Orgc->find('list', array(
'fields' => array('Orgc.id', 'Orgc.name')
));
return $export->export($attributes, $orgs, $valueField, $allowedlist, $instanceString);
}
/**
* @param int|false $jobId
* @param int|false $eventId