mirror of https://github.com/MISP/MISP
Merge remote-tracking branch 'origin/develop' into feature-workflows-2
commit
99a76812bc
|
@ -40,6 +40,9 @@ class EventShell extends AppShell
|
|||
'event_id' => ['help' => __('Event ID'), 'required' => true],
|
||||
'user_id' => ['help' => __('User ID'), 'required' => true],
|
||||
],
|
||||
'options' => [
|
||||
'send' => ['help' => __('Send email to given user'), 'boolean' => true],
|
||||
],
|
||||
],
|
||||
]);
|
||||
$parser->addSubcommand('duplicateTags', [
|
||||
|
@ -607,6 +610,7 @@ class EventShell extends AppShell
|
|||
public function testEventNotificationEmail()
|
||||
{
|
||||
list($eventId, $userId) = $this->args;
|
||||
$send = $this->param('send');
|
||||
|
||||
$user = $this->getUser($userId);
|
||||
$eventForUser = $this->Event->fetchEvent($user, [
|
||||
|
@ -626,10 +630,16 @@ class EventShell extends AppShell
|
|||
App::uses('SendEmail', 'Tools');
|
||||
App::uses('GpgTool', 'Tools');
|
||||
$sendEmail = new SendEmail(GpgTool::initializeGpg());
|
||||
$sendEmail->setTransport('Debug');
|
||||
if (!$send) {
|
||||
$sendEmail->setTransport('Debug');
|
||||
}
|
||||
$result = $sendEmail->sendToUser(['User' => $user], null, $emailTemplate);
|
||||
|
||||
echo $result['contents']['headers'] . "\n\n" . $result['contents']['message'] . "\n";
|
||||
if ($send) {
|
||||
var_dump($result);
|
||||
} else {
|
||||
echo $result['contents']['headers'] . "\n\n" . $result['contents']['message'] . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,6 +4,7 @@ App::uses('Controller', 'Controller');
|
|||
App::uses('File', 'Utility');
|
||||
App::uses('RequestRearrangeTool', 'Tools');
|
||||
App::uses('BlowfishConstantPasswordHasher', 'Controller/Component/Auth');
|
||||
App::uses('BetterCakeEventManager', 'Tools');
|
||||
|
||||
/**
|
||||
* Application Controller
|
||||
|
@ -1259,17 +1260,17 @@ class AppController extends Controller
|
|||
]);
|
||||
}
|
||||
}
|
||||
/** @var TmpFileTool $final */
|
||||
$final = $model->restSearch($user, $returnFormat, $filters, false, false, $elementCounter, $renderView);
|
||||
if (!empty($renderView) && !empty($final)) {
|
||||
if ($renderView) {
|
||||
$this->layout = false;
|
||||
$final = json_decode($final->intoString(), true);
|
||||
foreach ($final as $key => $data) {
|
||||
$this->set($key, $data);
|
||||
}
|
||||
$this->set($final);
|
||||
$this->render('/Events/module_views/' . $renderView);
|
||||
} else {
|
||||
$filename = $this->RestSearch->getFilename($filters, $scope, $responseType);
|
||||
return $this->RestResponse->viewData($final, $responseType, false, true, $filename, array('X-Result-Count' => $elementCounter, 'X-Export-Module-Used' => $returnFormat, 'X-Response-Format' => $responseType));
|
||||
$headers = ['X-Result-Count' => $elementCounter, 'X-Export-Module-Used' => $returnFormat, 'X-Response-Format' => $responseType];
|
||||
return $this->RestResponse->viewData($final, $responseType, false, true, $filename, $headers);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1443,6 +1444,16 @@ class AppController extends Controller
|
|||
return parent::_getViewObject();
|
||||
}
|
||||
|
||||
public function getEventManager()
|
||||
{
|
||||
if (empty($this->_eventManager)) {
|
||||
$this->_eventManager = new BetterCakeEventManager();
|
||||
$this->_eventManager->attach($this->Components);
|
||||
$this->_eventManager->attach($this);
|
||||
}
|
||||
return $this->_eventManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close session without writing changes to them and return current user.
|
||||
* @return array
|
||||
|
@ -1462,16 +1473,7 @@ class AppController extends Controller
|
|||
protected function _jsonDecode($dataToDecode)
|
||||
{
|
||||
try {
|
||||
if (defined('JSON_THROW_ON_ERROR')) {
|
||||
// JSON_THROW_ON_ERROR is supported since PHP 7.3
|
||||
return json_decode($dataToDecode, true, 512, JSON_THROW_ON_ERROR);
|
||||
} else {
|
||||
$decoded = json_decode($dataToDecode, true);
|
||||
if ($decoded === null) {
|
||||
throw new UnexpectedValueException('Could not parse JSON: ' . json_last_error_msg(), json_last_error());
|
||||
}
|
||||
return $decoded;
|
||||
}
|
||||
return JsonTool::decode($dataToDecode);
|
||||
} catch (Exception $e) {
|
||||
throw new HttpException('Invalid JSON input. Make sure that the JSON input is a correctly formatted JSON string. This request has been blocked to avoid an unfiltered request.', 405, $e);
|
||||
}
|
||||
|
|
|
@ -738,6 +738,7 @@ class ACLComponent extends Component
|
|||
'verifyGPG' => array(),
|
||||
'view' => array('*'),
|
||||
'getGpgPublicKey' => array('*'),
|
||||
'unsubscribe' => ['*'],
|
||||
),
|
||||
'userSettings' => array(
|
||||
'index' => array('*'),
|
||||
|
@ -1001,6 +1002,8 @@ class ACLComponent extends Component
|
|||
|
||||
private function __findAllFunctions()
|
||||
{
|
||||
$functionsToIgnore = ['beforeFilter', 'afterFilter', 'beforeRender', 'getEventManager'];
|
||||
|
||||
$functionFinder = '/function[\s\n]+(\S+)[\s\n]*\(/';
|
||||
$dir = new Folder(APP . 'Controller');
|
||||
$files = $dir->find('.*\.php');
|
||||
|
@ -1011,11 +1014,11 @@ class ACLComponent extends Component
|
|||
$controllerName = '*';
|
||||
}
|
||||
$functionArray = array();
|
||||
$fileContents = file_get_contents(APP . 'Controller' . DS . $file);
|
||||
$fileContents = FileAccessTool::readFromFile(APP . 'Controller' . DS . $file);
|
||||
$fileContents = preg_replace('/\/\*[^\*]+?\*\//', '', $fileContents);
|
||||
preg_match_all($functionFinder, $fileContents, $functionArray);
|
||||
foreach ($functionArray[1] as $function) {
|
||||
if ($function[0] !== '_' && $function !== 'beforeFilter' && $function !== 'afterFilter' && $function !== 'beforeRender') {
|
||||
if ($function[0] !== '_' && !in_array($function, $functionsToIgnore, true)) {
|
||||
$results[$controllerName][] = $function;
|
||||
}
|
||||
}
|
||||
|
@ -1036,8 +1039,7 @@ class ACLComponent extends Component
|
|||
$missing = array();
|
||||
foreach ($results as $controller => $functions) {
|
||||
foreach ($functions as $function) {
|
||||
if (!isset(self::ACL_LIST[$controller])
|
||||
|| !in_array($function, array_keys(self::ACL_LIST[$controller]))) {
|
||||
if (!isset(self::ACL_LIST[$controller]) || !in_array($function, array_keys(self::ACL_LIST[$controller]))) {
|
||||
$missing[$controller][] = $function;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,21 @@
|
|||
<?php
|
||||
App::uses('BlowfishPasswordHasher', 'Controller/Component/Auth');
|
||||
App::uses('AbstractPasswordHasher', 'Controller/Component/Auth');
|
||||
|
||||
class BlowfishConstantPasswordHasher extends BlowfishPasswordHasher
|
||||
class BlowfishConstantPasswordHasher extends AbstractPasswordHasher
|
||||
{
|
||||
/**
|
||||
* @param string $password
|
||||
* @return string
|
||||
*/
|
||||
public function hash($password)
|
||||
{
|
||||
$hash = password_hash($password, PASSWORD_BCRYPT);
|
||||
if ($hash === false) {
|
||||
throw new RuntimeException('Could not generate hashed password');
|
||||
}
|
||||
return $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password
|
||||
* @param string $hashedPassword
|
||||
|
@ -10,6 +23,6 @@ class BlowfishConstantPasswordHasher extends BlowfishPasswordHasher
|
|||
*/
|
||||
public function check($password, $hashedPassword)
|
||||
{
|
||||
return hash_equals($hashedPassword, Security::hash($password, 'blowfish', $hashedPassword));
|
||||
return password_verify($password, $hashedPassword);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -619,7 +619,7 @@ class EventsController extends AppController
|
|||
if (empty($usersToMatch)) {
|
||||
$nothing = true;
|
||||
} else {
|
||||
$this->paginate['conditions']['AND'][] = ['Event.user_id' => array_unique($usersToMatch)];
|
||||
$this->paginate['conditions']['AND'][] = ['Event.user_id' => array_unique($usersToMatch, SORT_REGULAR)];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -3328,20 +3328,40 @@ class EventsController extends AppController
|
|||
|
||||
public function restSearchExport($id = null, $returnFormat = null)
|
||||
{
|
||||
if (is_null($returnFormat)) {
|
||||
if (is_numeric($id)) {
|
||||
$idList = [$id];
|
||||
} else {
|
||||
$idList = $this->_jsonDecode($id);
|
||||
}
|
||||
if ($returnFormat === null) {
|
||||
$exportFormats = [
|
||||
'attack' => __('Attack matrix'),
|
||||
'attack-sightings' => __('Attack matrix by sightings'),
|
||||
'context' => __('Aggregated context data'),
|
||||
'context-markdown' => __('Aggregated context data as Markdown'),
|
||||
'csv' => __('CSV'),
|
||||
'hashes' => __('Hashes'),
|
||||
'hosts' => __('Hosts file'),
|
||||
'json' => __('MISP JSON'),
|
||||
'netfilter' => __('Netfilter'),
|
||||
'opendata' => __('Open data'),
|
||||
'openioc' => __('OpenIOC'),
|
||||
'rpz' => __('RPZ'),
|
||||
'snort' => __('Snort rules'),
|
||||
'stix' => __('STIX 1 XML'),
|
||||
'stix-json' => __('STIX 1 JSON'),
|
||||
'stix2' => __('STIX 2'),
|
||||
'suricata' => __('Suricata rules'),
|
||||
'text' => __('Text file'),
|
||||
'xml' => __('MISP XML'),
|
||||
'yara' => __('YARA rules'),
|
||||
'yara-json' => __('YARA rules (JSON)'),
|
||||
];
|
||||
|
||||
$idList = is_numeric($id) ? [$id] : $this->_jsonDecode($id);
|
||||
if (empty($idList)) {
|
||||
throw new NotFoundException(__('Invalid input.'));
|
||||
}
|
||||
$this->set('idList', $idList);
|
||||
$this->set('exportFormats', array_keys($this->Event->validFormats));
|
||||
$this->set('exportFormats', $exportFormats);
|
||||
$this->render('ajax/eventRestSearchExportConfirmationForm');
|
||||
} else {
|
||||
$returnFormat = empty($this->Event->validFormats[$returnFormat]) ? 'json' : $returnFormat;
|
||||
$returnFormat = !isset($this->Event->validFormats[$returnFormat]) ? 'json' : $returnFormat;
|
||||
$idList = $id;
|
||||
if (!is_array($idList)) {
|
||||
if (is_numeric($idList) || Validation::uuid($idList)) {
|
||||
|
@ -3354,19 +3374,17 @@ class EventsController extends AppController
|
|||
throw new NotFoundException(__('Invalid input.'));
|
||||
}
|
||||
$filters = [
|
||||
'eventid' => $idList
|
||||
'eventid' => $idList,
|
||||
'published' => [true, false], // fetch published and unpublished events
|
||||
];
|
||||
|
||||
$elementCounter = 0;
|
||||
$renderView = false;
|
||||
$validFormat = $this->Event->validFormats[$returnFormat];
|
||||
$responseType = $validFormat[0];
|
||||
$responseType = $this->Event->validFormats[$returnFormat][0];
|
||||
$final = $this->Event->restSearch($this->Auth->user(), $returnFormat, $filters, false, false, $elementCounter, $renderView);
|
||||
if (!empty($renderView) && !empty($final)) {
|
||||
if ($renderView) {
|
||||
$final = json_decode($final->intoString(), true);
|
||||
foreach ($final as $key => $data) {
|
||||
$this->set($key, $data);
|
||||
}
|
||||
$this->set($final);
|
||||
$this->set('responseType', $responseType);
|
||||
$this->set('returnFormat', $returnFormat);
|
||||
$this->set('renderView', $renderView);
|
||||
|
|
|
@ -1922,7 +1922,7 @@ class ServersController extends AppController
|
|||
$dbVersion = $this->AdminSetting->getSetting('db_version');
|
||||
$updateProgress = $this->Server->getUpdateProgress();
|
||||
$updateProgress['db_version'] = $dbVersion;
|
||||
$maxUpdateNumber = max(array_keys($this->Server->db_changes));
|
||||
$maxUpdateNumber = max(array_keys(Server::DB_CHANGES));
|
||||
$updateProgress['complete_update_remaining'] = max($maxUpdateNumber - $dbVersion, 0);
|
||||
$updateProgress['update_locked'] = $this->Server->isUpdateLocked();
|
||||
$updateProgress['lock_remaining_time'] = $this->Server->getLockRemainingTime();
|
||||
|
|
|
@ -118,6 +118,24 @@ class UsersController extends AppController
|
|||
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Something went wrong, please try again later.')), 'status'=>200, 'type' => 'json'));
|
||||
}
|
||||
|
||||
public function unsubscribe($code)
|
||||
{
|
||||
$user = $this->Auth->user();
|
||||
|
||||
if (!hash_equals($this->User->unsubscribeCode($user), rtrim($code, '.'))) {
|
||||
$this->Flash->error(__('Invalid unsubscribe code.'));
|
||||
$this->redirect(['action' => 'view', 'me']);
|
||||
}
|
||||
|
||||
if ($user['autoalert']) {
|
||||
$this->User->updateField($this->Auth->user(), 'autoalert', false);
|
||||
$this->Flash->success(__('Successfully unsubscribed from event alert.'));
|
||||
} else {
|
||||
$this->Flash->info(__('Already unsubscribed from event alert.'));
|
||||
}
|
||||
$this->redirect(['action' => 'view', 'me']);
|
||||
}
|
||||
|
||||
public function edit()
|
||||
{
|
||||
$currentUser = $this->User->find('first', array(
|
||||
|
|
|
@ -6,16 +6,16 @@ class HashesExport
|
|||
'flatten' => 1
|
||||
);
|
||||
|
||||
public $validTypes = array(
|
||||
const VALID_TYPES = array(
|
||||
'simple' => array(
|
||||
'md5', 'sha1', 'sha256', 'sha224', 'sha512', 'sha512/224', 'sha512/256', 'ssdeep', 'imphash', 'tlsh',
|
||||
'x509-fingerprint-sha1', 'x509-fingerprint-md5', 'x509-fingerprint-sha256', 'pehash', 'authentihash',
|
||||
'impfuzzy'
|
||||
'md5', 'sha1', 'sha256', 'sha224', 'sha384', 'sha512', 'sha512/224', 'sha512/256', 'sha3-224', 'sha3-256',
|
||||
'sha3-384', 'sha3-512', 'ssdeep', 'imphash', 'tlsh', 'x509-fingerprint-sha1', 'x509-fingerprint-md5',
|
||||
'x509-fingerprint-sha256', 'pehash', 'authentihash', 'impfuzzy'
|
||||
),
|
||||
'composite' => array(
|
||||
'malware-sample', 'filename|md5', 'filename|sha1', 'filename|sha256', 'filename|sha224', 'filename|sha512',
|
||||
'filename|sha512/224', 'filename|sha512/256', 'filename|ssdeep', 'filename|imphash', 'filename|tlsh',
|
||||
'x509-fingerprint-sha1', 'x509-fingerprint-md5', 'x509-fingerprint-sha256', 'filename|pehash',
|
||||
'filename|sha512/224', 'filename|sha512/256', 'filename|sha3-224', 'filename|sha3-256', 'filename|sha3-384',
|
||||
'filename|sha3-512', 'filename|ssdeep', 'filename|imphash', 'filename|tlsh', 'filename|pehash',
|
||||
'filename|authentihash', 'filename|impfuzzy'
|
||||
)
|
||||
);
|
||||
|
@ -23,18 +23,17 @@ class HashesExport
|
|||
public function handler($data, $options = array())
|
||||
{
|
||||
if ($options['scope'] === 'Attribute') {
|
||||
if (in_array($data['Attribute']['type'], $this->validTypes['composite'])) {
|
||||
if (in_array($data['Attribute']['type'], self::VALID_TYPES['composite'], true)) {
|
||||
return explode('|', $data['Attribute']['value'])[1];
|
||||
} else if (in_array($data['Attribute']['type'], $this->validTypes['simple'])) {
|
||||
} else if (in_array($data['Attribute']['type'], self::VALID_TYPES['simple'], true)) {
|
||||
return $data['Attribute']['value'];
|
||||
}
|
||||
}
|
||||
if ($options['scope'] === 'Event') {
|
||||
} else if ($options['scope'] === 'Event') {
|
||||
$result = array();
|
||||
foreach ($data['Attribute'] as $attribute) {
|
||||
if (in_array($attribute['type'], $this->validTypes['composite'])) {
|
||||
if (in_array($attribute['type'], self::VALID_TYPES['composite'], true)) {
|
||||
$result[] = explode('|', $attribute['value'])[1];
|
||||
} else if (in_array($attribute['type'], $this->validTypes['simple'])) {
|
||||
} else if (in_array($attribute['type'], self::VALID_TYPES['simple'], true)) {
|
||||
$result[] = $attribute['value'];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
class JsonExport
|
||||
{
|
||||
public $non_restrictive_export = true;
|
||||
public $non_restrictive_export = true;
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
|
@ -11,17 +11,17 @@ class JsonExport
|
|||
*/
|
||||
public function handler($data, $options = array())
|
||||
{
|
||||
if ($options['scope'] === 'Attribute') {
|
||||
return $this->__attributeHandler($data, $options);
|
||||
} else if($options['scope'] === 'Event') {
|
||||
return $this->__eventHandler($data, $options);
|
||||
} else if($options['scope'] === 'Object') {
|
||||
if ($options['scope'] === 'Attribute') {
|
||||
return $this->__attributeHandler($data, $options);
|
||||
} else if ($options['scope'] === 'Event') {
|
||||
return $this->__eventHandler($data, $options);
|
||||
} else if ($options['scope'] === 'Object') {
|
||||
return $this->__objectHandler($data, $options);
|
||||
} else if($options['scope'] === 'Sighting') {
|
||||
return $this->__sightingsHandler($data, $options);
|
||||
} else if($options['scope'] === 'GalaxyCluster') {
|
||||
return $this->__galaxyClusterHandler($data, $options);
|
||||
}
|
||||
} else if ($options['scope'] === 'Sighting') {
|
||||
return $this->__sightingsHandler($data, $options);
|
||||
} else if ($options['scope'] === 'GalaxyCluster') {
|
||||
return $this->__galaxyClusterHandler($data, $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,66 +29,68 @@ class JsonExport
|
|||
* @param array $options
|
||||
* @return Generator
|
||||
*/
|
||||
private function __eventHandler($event, $options = array())
|
||||
private function __eventHandler($event, $options = array())
|
||||
{
|
||||
App::uses('JSONConverterTool', 'Tools');
|
||||
return JSONConverterTool::streamConvert($event);
|
||||
}
|
||||
|
||||
private function __objectHandler($object, $options = array()) {
|
||||
App::uses('JSONConverterTool', 'Tools');
|
||||
return json_encode(JSONConverterTool::convertObject($object, false, true));
|
||||
return JSONConverterTool::streamConvert($event);
|
||||
}
|
||||
|
||||
private function __attributeHandler($attribute, $options = array())
|
||||
{
|
||||
$attribute = array_merge($attribute['Attribute'], $attribute);
|
||||
unset($attribute['Attribute']);
|
||||
if (isset($attribute['Object']) && empty($attribute['Object']['id'])) {
|
||||
unset($attribute['Object']);
|
||||
}
|
||||
$tagTypes = array('AttributeTag', 'EventTag');
|
||||
foreach($tagTypes as $tagType) {
|
||||
if (isset($attribute[$tagType])) {
|
||||
foreach ($attribute[$tagType] as $tk => $tag) {
|
||||
if ($tagType === 'EventTag') {
|
||||
$attribute[$tagType][$tk]['Tag']['inherited'] = 1;
|
||||
}
|
||||
$attribute['Tag'][] = $attribute[$tagType][$tk]['Tag'];
|
||||
}
|
||||
unset($attribute[$tagType]);
|
||||
}
|
||||
}
|
||||
unset($attribute['value1']);
|
||||
unset($attribute['value2']);
|
||||
return json_encode($attribute);
|
||||
}
|
||||
private function __objectHandler($object, $options = array())
|
||||
{
|
||||
App::uses('JSONConverterTool', 'Tools');
|
||||
return JsonTool::encode(JSONConverterTool::convertObject($object, false, true));
|
||||
}
|
||||
|
||||
private function __attributeHandler($attribute, $options = array())
|
||||
{
|
||||
$attribute = array_merge($attribute['Attribute'], $attribute);
|
||||
unset($attribute['Attribute']);
|
||||
if (isset($attribute['Object']) && empty($attribute['Object']['id'])) {
|
||||
unset($attribute['Object']);
|
||||
}
|
||||
$tagTypes = array('AttributeTag', 'EventTag');
|
||||
foreach ($tagTypes as $tagType) {
|
||||
if (isset($attribute[$tagType])) {
|
||||
foreach ($attribute[$tagType] as $tag) {
|
||||
if ($tagType === 'EventTag') {
|
||||
$tag['Tag']['inherited'] = 1;
|
||||
}
|
||||
$attribute['Tag'][] = $tag['Tag'];
|
||||
}
|
||||
unset($attribute[$tagType]);
|
||||
}
|
||||
}
|
||||
unset($attribute['value1']);
|
||||
unset($attribute['value2']);
|
||||
return JsonTool::encode($attribute);
|
||||
}
|
||||
|
||||
private function __sightingsHandler($sighting, $options = array())
|
||||
{
|
||||
return json_encode($sighting);
|
||||
return JsonTool::encode($sighting);
|
||||
}
|
||||
|
||||
private function __galaxyClusterHandler($cluster, $options = array())
|
||||
{
|
||||
return json_encode($cluster);
|
||||
return JsonTool::encode($cluster);
|
||||
}
|
||||
|
||||
public function header($options = array())
|
||||
{
|
||||
if ($options['scope'] === 'Attribute') {
|
||||
return '{"response": {"Attribute": [';
|
||||
} else {
|
||||
return '{"response": [';
|
||||
}
|
||||
if ($options['scope'] === 'Attribute') {
|
||||
return '{"response": {"Attribute": [';
|
||||
} else {
|
||||
return '{"response": [';
|
||||
}
|
||||
}
|
||||
|
||||
public function footer($options = array())
|
||||
{
|
||||
if ($options['scope'] === 'Attribute') {
|
||||
return ']}}' . PHP_EOL;
|
||||
} else {
|
||||
return ']}' . PHP_EOL;
|
||||
}
|
||||
if ($options['scope'] === 'Attribute') {
|
||||
return ']}}' . PHP_EOL;
|
||||
} else {
|
||||
return ']}' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
public function separator()
|
||||
|
|
|
@ -7,84 +7,125 @@ class NidsExport
|
|||
public $classtype = 'trojan-activity';
|
||||
|
||||
public $format = ""; // suricata (default), snort
|
||||
|
||||
public $supportedObjects = array('network-connection', 'ddos');
|
||||
|
||||
public $checkWhitelist = true;
|
||||
public $checkWhitelist = true;
|
||||
|
||||
public $additional_params = array(
|
||||
'contain' => array(
|
||||
'Event' => array(
|
||||
'fields' => array('threat_level_id')
|
||||
)
|
||||
),
|
||||
'flatten' => 1
|
||||
);
|
||||
public $additional_params = array(
|
||||
'contain' => array(
|
||||
'Event' => array(
|
||||
'fields' => array('threat_level_id')
|
||||
)
|
||||
),
|
||||
|
||||
public function handler($data, $options = array())
|
||||
{
|
||||
$continue = empty($format);
|
||||
$this->checkWhitelist = false;
|
||||
if ($options['scope'] === 'Attribute') {
|
||||
$this->export(
|
||||
array($data),
|
||||
$options['user']['nids_sid'],
|
||||
$options['returnFormat'],
|
||||
$continue
|
||||
);
|
||||
} else if ($options['scope'] === 'Event') {
|
||||
if (!empty($data['EventTag'])) {
|
||||
$data['Event']['EventTag'] = $data['EventTag'];
|
||||
}
|
||||
if (!empty($data['Attribute'])) {
|
||||
$this->__convertFromEventFormat($data['Attribute'], $data, $options, $continue);
|
||||
}
|
||||
if (!empty($data['Object'])) {
|
||||
foreach ($data['Object'] as $object) {
|
||||
$this->__convertFromEventFormat($object['Attribute'], $data, $options, $continue);
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
);
|
||||
|
||||
private function __convertFromEventFormat($attributes, $event, $options = array(), $continue = false) {
|
||||
$rearranged = array();
|
||||
foreach ($attributes as $attribute) {
|
||||
$attributeTag = array();
|
||||
if (!empty($attribute['AttributeTag'])) {
|
||||
$attributeTag = $attribute['AttributeTag'];
|
||||
unset($attribute['AttributeTag']);
|
||||
}
|
||||
$rearranged[] = array(
|
||||
'Attribute' => $attribute,
|
||||
'AttributeTag' => $attributeTag,
|
||||
'Event' => $event['Event']
|
||||
);
|
||||
}
|
||||
$this->export(
|
||||
$rearranged,
|
||||
$options['user']['nids_sid'],
|
||||
$options['returnFormat'],
|
||||
$continue
|
||||
);
|
||||
return true;
|
||||
public function handler($data, $options = array())
|
||||
{
|
||||
$continue = empty($format);
|
||||
$this->checkWhitelist = false;
|
||||
if ($options['scope'] === 'Attribute') {
|
||||
$this->export(
|
||||
array($data),
|
||||
$options['user']['nids_sid'],
|
||||
$options['returnFormat'],
|
||||
$continue
|
||||
);
|
||||
} else if ($options['scope'] === 'Event') {
|
||||
if (!empty($data['EventTag'])) {
|
||||
$data['Event']['EventTag'] = $data['EventTag'];
|
||||
}
|
||||
if (!empty($data['Attribute'])) {
|
||||
$this->__convertFromEventFormat($data['Attribute'], $data, $options, $continue);
|
||||
}
|
||||
if (!empty($data['Object'])) {
|
||||
$this->__convertFromEventFormatObject($data['Object'], $data, $options, $continue);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
}
|
||||
private function __convertFromEventFormat($attributes, $event, $options = array(), $continue = false) {
|
||||
|
||||
public function header($options = array())
|
||||
{
|
||||
$this->explain();
|
||||
return '';
|
||||
}
|
||||
$rearranged = array();
|
||||
foreach ($attributes as $attribute) {
|
||||
$attributeTag = array();
|
||||
if (!empty($attribute['AttributeTag'])) {
|
||||
$attributeTag = $attribute['AttributeTag'];
|
||||
unset($attribute['AttributeTag']);
|
||||
}
|
||||
$rearranged[] = array(
|
||||
'Attribute' => $attribute,
|
||||
'AttributeTag' => $attributeTag,
|
||||
'Event' => $event['Event']
|
||||
);
|
||||
}
|
||||
$this->export(
|
||||
$rearranged,
|
||||
$options['user']['nids_sid'],
|
||||
$options['returnFormat'],
|
||||
$continue
|
||||
);
|
||||
return true;
|
||||
|
||||
public function footer()
|
||||
{
|
||||
return implode ("\n", $this->rules);
|
||||
}
|
||||
}
|
||||
|
||||
public function separator()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
private function __convertFromEventFormatObject($objects, $event, $options = array(), $continue = false) {
|
||||
|
||||
$rearranged = array();
|
||||
foreach ($objects as $object) {
|
||||
|
||||
if(in_array($object['name'], $this->supportedObjects)){
|
||||
|
||||
$objectTag = array();
|
||||
|
||||
foreach($object['Attribute'] as $attribute) {
|
||||
|
||||
if (!empty($attribute['AttributeTag'])) {
|
||||
$objectTag = array_merge($objectTag, $attribute['AttributeTag']);
|
||||
unset($attribute['AttributeTag']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$rearranged[] = array(
|
||||
'Attribute' => $object, // Using 'Attribute' instead of 'Object' to comply with function export
|
||||
'AttributeTag' => $objectTag, // Using 'AttributeTag' instead of 'ObjectTag' to comply with function export
|
||||
'Event' => $event['Event']
|
||||
);
|
||||
|
||||
} else { // In case no custom export exists for the object, the approach falls back to the attribute case
|
||||
$this->__convertFromEventFormat($object['Attribute'], $event, $options, $continue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$this->export(
|
||||
$rearranged,
|
||||
$options['user']['nids_sid'],
|
||||
$options['returnFormat'],
|
||||
$continue
|
||||
);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function header($options = array())
|
||||
{
|
||||
$this->explain();
|
||||
return '';
|
||||
}
|
||||
|
||||
public function footer()
|
||||
{
|
||||
return implode ("\n", $this->rules);
|
||||
}
|
||||
|
||||
public function separator()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function explain()
|
||||
{
|
||||
|
@ -93,7 +134,7 @@ class NidsExport
|
|||
$this->rules[] = '# These NIDS rules contain some variables that need to exist in your configuration.';
|
||||
$this->rules[] = '# Make sure you have set:';
|
||||
$this->rules[] = '#';
|
||||
$this->rules[] = '# $HOME_NET - Your internal network range';
|
||||
$this->rules[] = '# $HOME_NET - Your internal network range';
|
||||
$this->rules[] = '# $EXTERNAL_NET - The network considered as outside';
|
||||
$this->rules[] = '# $SMTP_SERVERS - All your internal SMTP servers';
|
||||
$this->rules[] = '# $HTTP_PORTS - The ports used to contain HTTP traffic (not required with suricata export)';
|
||||
|
@ -106,10 +147,10 @@ class NidsExport
|
|||
public function export($items, $startSid, $format="suricata", $continue = false)
|
||||
{
|
||||
$this->format = $format;
|
||||
if ($this->checkWhitelist && !isset($this->Whitelist)) {
|
||||
$this->Whitelist = ClassRegistry::init('Whitelist');
|
||||
$this->whitelist = $this->Whitelist->getBlockedValues();
|
||||
}
|
||||
if ($this->checkWhitelist && !isset($this->Whitelist)) {
|
||||
$this->Whitelist = ClassRegistry::init('Whitelist');
|
||||
$this->whitelist = $this->Whitelist->getBlockedValues();
|
||||
}
|
||||
|
||||
// output a short explanation
|
||||
if (!$continue) {
|
||||
|
@ -119,20 +160,20 @@ class NidsExport
|
|||
foreach ($items as $item) {
|
||||
// retrieve all tags for this item to add them to the msg
|
||||
$tagsArray = [];
|
||||
if (!empty($item['AttributeTag'])) {
|
||||
foreach ($item['AttributeTag'] as $tag_attr) {
|
||||
if (array_key_exists('name', $tag_attr['Tag'])) {
|
||||
array_push($tagsArray, $tag_attr['Tag']['name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($item['Event']['EventTag'])) {
|
||||
foreach ($item['Event']['EventTag'] as $tag_event) {
|
||||
if (array_key_exists('name', $tag_event['Tag'])) {
|
||||
array_push($tagsArray, $tag_event['Tag']['name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($item['AttributeTag'])) {
|
||||
foreach ($item['AttributeTag'] as $tag_attr) {
|
||||
if (array_key_exists('name', $tag_attr['Tag'])) {
|
||||
array_push($tagsArray, $tag_attr['Tag']['name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($item['Event']['EventTag'])) {
|
||||
foreach ($item['Event']['EventTag'] as $tag_event) {
|
||||
if (array_key_exists('name', $tag_event['Tag'])) {
|
||||
array_push($tagsArray, $tag_event['Tag']['name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
$ruleFormatMsgTags = implode(",", $tagsArray);
|
||||
|
||||
# proto src_ip src_port direction dst_ip dst_port msg rule_content tag sid rev
|
||||
|
@ -142,69 +183,179 @@ class NidsExport
|
|||
|
||||
$sid = $startSid + ($item['Attribute']['id'] * 10); // leave 9 possible rules per attribute type
|
||||
$sid++;
|
||||
switch ($item['Attribute']['type']) {
|
||||
// LATER nids - test all the snort attributes
|
||||
// LATER nids - add the tag keyword in the rules to capture network traffic
|
||||
// LATER nids - sanitize every $attribute['value'] to not conflict with snort
|
||||
case 'ip-dst':
|
||||
$this->ipDstRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'ip-src':
|
||||
$this->ipSrcRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'ip-dst|port':
|
||||
$this->ipDstRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'ip-src|port':
|
||||
$this->ipSrcRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'email':
|
||||
$this->emailSrcRule($ruleFormat, $item['Attribute'], $sid++);
|
||||
$this->emailDstRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'email-src':
|
||||
$this->emailSrcRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'email-dst':
|
||||
$this->emailDstRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'email-subject':
|
||||
$this->emailSubjectRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'email-attachment':
|
||||
$this->emailAttachmentRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'domain':
|
||||
$this->domainRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'domain|ip':
|
||||
$this->domainIpRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'hostname':
|
||||
$this->hostnameRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'url':
|
||||
$this->urlRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'user-agent':
|
||||
$this->userAgentRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'ja3-fingerprint-md5':
|
||||
$this->ja3Rule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'ja3s-fingerprint-md5': // Atribute type doesn't exists yet (2020-12-10) but ready when created.
|
||||
$this->ja3sRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'snort':
|
||||
$this->snortRule($ruleFormat, $item['Attribute'], $sid, $ruleFormatMsg, $ruleFormatReference);
|
||||
// no break
|
||||
default:
|
||||
break;
|
||||
|
||||
if(!empty($item['Attribute']['type'])) { // item is an 'Attribute'
|
||||
|
||||
switch ($item['Attribute']['type']) {
|
||||
// LATER nids - test all the snort attributes
|
||||
// LATER nids - add the tag keyword in the rules to capture network traffic
|
||||
// LATER nids - sanitize every $attribute['value'] to not conflict with snort
|
||||
case 'ip-dst':
|
||||
$this->ipDstRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'ip-src':
|
||||
$this->ipSrcRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'ip-dst|port':
|
||||
$this->ipDstRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'ip-src|port':
|
||||
$this->ipSrcRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'email':
|
||||
$this->emailSrcRule($ruleFormat, $item['Attribute'], $sid);
|
||||
$this->emailDstRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'email-src':
|
||||
$this->emailSrcRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'email-dst':
|
||||
$this->emailDstRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'email-subject':
|
||||
$this->emailSubjectRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'email-attachment':
|
||||
$this->emailAttachmentRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'domain':
|
||||
$this->domainRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'domain|ip':
|
||||
$this->domainIpRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'hostname':
|
||||
$this->hostnameRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'url':
|
||||
$this->urlRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'user-agent':
|
||||
$this->userAgentRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'ja3-fingerprint-md5':
|
||||
$this->ja3Rule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'ja3s-fingerprint-md5': // Atribute type doesn't exists yet (2020-12-10) but ready when created.
|
||||
$this->ja3sRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'snort':
|
||||
$this->snortRule($ruleFormat, $item['Attribute'], $sid, $ruleFormatMsg, $ruleFormatReference);
|
||||
// no break
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} else if(!empty($item['Attribute']['name'])) { // Item is an 'Object'
|
||||
|
||||
switch ($item['Attribute']['name']) {
|
||||
case 'network-connection':
|
||||
$this->networkConnectionRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
case 'ddos':
|
||||
$this->ddosRule($ruleFormat, $item['Attribute'], $sid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $this->rules;
|
||||
}
|
||||
|
||||
public function networkConnectionRule($ruleFormat, $object, &$sid)
|
||||
{
|
||||
|
||||
$attributes = NidsExport::getObjectAttributes($object);
|
||||
|
||||
if(!array_key_exists('layer4-protocol', $attributes)){
|
||||
$attributes['layer4-protocol'] = 'ip'; // If layer-4 protocol is unknown, we roll-back to layer-3 ('ip')
|
||||
}
|
||||
if(!array_key_exists('ip-src', $attributes)){
|
||||
$attributes['ip-src'] = '$HOME_NET'; // If ip-src is unknown, we roll-back to $HOME_NET
|
||||
}
|
||||
if(!array_key_exists('ip-dst', $attributes)){
|
||||
$attributes['ip-dst'] = '$HOME_NET'; // If ip-dst is unknown, we roll-back to $HOME_NET
|
||||
}
|
||||
if(!array_key_exists('src-port', $attributes)){
|
||||
$attributes['src-port'] = 'any'; // If src-port is unknown, we roll-back to 'any'
|
||||
}
|
||||
if(!array_key_exists('dst-port', $attributes)){
|
||||
$attributes['dst-port'] = 'any'; // If dst-port is unknown, we roll-back to 'any'
|
||||
}
|
||||
|
||||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
false,
|
||||
$attributes['layer4-protocol'], // proto
|
||||
$attributes['ip-src'], // src_ip
|
||||
$attributes['src-port'], // src_port
|
||||
'->', // direction
|
||||
$attributes['ip-dst'], // dst_ip
|
||||
$attributes['dst-port'], // dst_port
|
||||
'Network connection between ' . $attributes['ip-src'] . ' and ' . $attributes['ip-dst'], // msg
|
||||
'', // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function ddosRule($ruleFormat, $object, &$sid)
|
||||
{
|
||||
|
||||
$attributes = NidsExport::getObjectAttributes($object);
|
||||
|
||||
if(!array_key_exists('protocol', $attributes)){
|
||||
$attributes['protocol'] = 'ip'; // If protocol is unknown, we roll-back to 'ip'
|
||||
}
|
||||
if(!array_key_exists('ip-src', $attributes)){
|
||||
$attributes['ip-src'] = '$HOME_NET'; // If ip-src is unknown, we roll-back to $HOME_NET
|
||||
}
|
||||
if(!array_key_exists('ip-dst', $attributes)){
|
||||
$attributes['ip-dst'] = '$HOME_NET'; // If ip-dst is unknown, we roll-back to $HOME_NET
|
||||
}
|
||||
if(!array_key_exists('src-port', $attributes)){
|
||||
$attributes['src-port'] = 'any'; // If src-port is unknown, we roll-back to 'any'
|
||||
}
|
||||
if(!array_key_exists('dst-port', $attributes)){
|
||||
$attributes['dst-port'] = 'any'; // If dst-port is unknown, we roll-back to 'any'
|
||||
}
|
||||
|
||||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
false,
|
||||
$attributes['protocol'], // proto
|
||||
$attributes['ip-src'], // src_ip
|
||||
$attributes['src-port'], // src_port
|
||||
'->', // direction
|
||||
$attributes['ip-dst'], // dst_ip
|
||||
$attributes['dst-port'], // dst_port
|
||||
'DDOS attack detected between ' . $attributes['ip-src'] . ' and ' . $attributes['ip-dst'], // msg
|
||||
'', // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public static function getObjectAttributes($object)
|
||||
{
|
||||
|
||||
$attributes = array();
|
||||
|
||||
foreach ($object['Attribute'] as $attribute) {
|
||||
$attributes[$attribute['object_relation']] = $attribute['value'];
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
public function domainIpRule($ruleFormat, $attribute, &$sid)
|
||||
{
|
||||
$values = explode('|', $attribute['value']);
|
||||
|
@ -225,17 +376,17 @@ class NidsExport
|
|||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'ip', // proto
|
||||
'$HOME_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
$ipport[0], // dst_ip
|
||||
$ipport[1], // dst_port
|
||||
'Outgoing To IP: ' . $attribute['value'], // msg
|
||||
'', // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'ip', // proto
|
||||
'$HOME_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
$ipport[0], // dst_ip
|
||||
$ipport[1], // dst_port
|
||||
'Outgoing To IP: ' . $attribute['value'], // msg
|
||||
'', // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -246,17 +397,17 @@ class NidsExport
|
|||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'ip', // proto
|
||||
$ipport[0], // src_ip
|
||||
$ipport[1], // src_port
|
||||
'->', // direction
|
||||
'$HOME_NET', // dst_ip
|
||||
'any', // dst_port
|
||||
'Incoming From IP: ' . $attribute['value'], // msg
|
||||
'', // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'ip', // proto
|
||||
$ipport[0], // src_ip
|
||||
$ipport[1], // src_port
|
||||
'->', // direction
|
||||
'$HOME_NET', // dst_ip
|
||||
'any', // dst_port
|
||||
'Incoming From IP: ' . $attribute['value'], // msg
|
||||
'', // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -268,17 +419,17 @@ class NidsExport
|
|||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'tcp', // proto
|
||||
'$EXTERNAL_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$SMTP_SERVERS', // dst_ip
|
||||
'25', // dst_port
|
||||
'Source Email Address: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'tcp', // proto
|
||||
'$EXTERNAL_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$SMTP_SERVERS', // dst_ip
|
||||
'25', // dst_port
|
||||
'Source Email Address: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -290,17 +441,17 @@ class NidsExport
|
|||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'tcp', // proto
|
||||
'$EXTERNAL_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$SMTP_SERVERS', // dst_ip
|
||||
'25', // dst_port
|
||||
'Destination Email Address: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'tcp', // proto
|
||||
'$EXTERNAL_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$SMTP_SERVERS', // dst_ip
|
||||
'25', // dst_port
|
||||
'Destination Email Address: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -313,17 +464,17 @@ class NidsExport
|
|||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'tcp', // proto
|
||||
'$EXTERNAL_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$SMTP_SERVERS', // dst_ip
|
||||
'25', // dst_port
|
||||
'Bad Email Subject', // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'tcp', // proto
|
||||
'$EXTERNAL_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$SMTP_SERVERS', // dst_ip
|
||||
'25', // dst_port
|
||||
'Bad Email Subject', // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -336,17 +487,17 @@ class NidsExport
|
|||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'tcp', // proto
|
||||
'$EXTERNAL_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$SMTP_SERVERS', // dst_ip
|
||||
'25', // dst_port
|
||||
'Bad Email Attachment', // msg
|
||||
$content, // rule_content // LATER nids - test and finetune this snort rule https://secure.wikimedia.org/wikipedia/en/wiki/MIME#Content-Disposition
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'tcp', // proto
|
||||
'$EXTERNAL_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$SMTP_SERVERS', // dst_ip
|
||||
'25', // dst_port
|
||||
'Bad Email Attachment', // msg
|
||||
$content, // rule_content // LATER nids - test and finetune this snort rule https://secure.wikimedia.org/wikipedia/en/wiki/MIME#Content-Disposition
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -358,33 +509,33 @@ class NidsExport
|
|||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'udp', // proto
|
||||
'any', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'any', // dst_ip
|
||||
'53', // dst_port
|
||||
'Hostname: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'udp', // proto
|
||||
'any', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'any', // dst_ip
|
||||
'53', // dst_port
|
||||
'Hostname: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
$sid++;
|
||||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'tcp', // proto
|
||||
'any', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'any', // dst_ip
|
||||
'53', // dst_port
|
||||
'Hostname: ' . $attribute['value'], // msg
|
||||
$content. ' flow:established;', // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'tcp', // proto
|
||||
'any', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'any', // dst_ip
|
||||
'53', // dst_port
|
||||
'Hostname: ' . $attribute['value'], // msg
|
||||
$content. ' flow:established;', // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
$sid++;
|
||||
// also do http requests
|
||||
|
@ -392,17 +543,17 @@ class NidsExport
|
|||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'tcp', // proto
|
||||
'$HOME_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$EXTERNAL_NET', // dst_ip
|
||||
'$HTTP_PORTS', // dst_port
|
||||
'Outgoing HTTP Hostname: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'tcp', // proto
|
||||
'$HOME_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$EXTERNAL_NET', // dst_ip
|
||||
'$HTTP_PORTS', // dst_port
|
||||
'Outgoing HTTP Hostname: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -414,33 +565,33 @@ class NidsExport
|
|||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'udp', // proto
|
||||
'any', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'any', // dst_ip
|
||||
'53', // dst_port
|
||||
'Domain: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'udp', // proto
|
||||
'any', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'any', // dst_ip
|
||||
'53', // dst_port
|
||||
'Domain: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
$sid++;
|
||||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'tcp', // proto
|
||||
'any', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'any', // dst_ip
|
||||
'53', // dst_port
|
||||
'Domain: ' . $attribute['value'], // msg
|
||||
$content. ' flow:established;', // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'tcp', // proto
|
||||
'any', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'any', // dst_ip
|
||||
'53', // dst_port
|
||||
'Domain: ' . $attribute['value'], // msg
|
||||
$content. ' flow:established;', // rule_content
|
||||
'', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
$sid++;
|
||||
// also do http requests,
|
||||
|
@ -448,17 +599,17 @@ class NidsExport
|
|||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'tcp', // proto
|
||||
'$HOME_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$EXTERNAL_NET', // dst_ip
|
||||
'$HTTP_PORTS', // dst_port
|
||||
'Outgoing HTTP Domain: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'tcp', // proto
|
||||
'$HOME_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$EXTERNAL_NET', // dst_ip
|
||||
'$HTTP_PORTS', // dst_port
|
||||
'Outgoing HTTP Domain: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -473,17 +624,17 @@ class NidsExport
|
|||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'tcp', // proto
|
||||
'$HOME_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$EXTERNAL_NET', // dst_ip
|
||||
'$HTTP_PORTS', // dst_port
|
||||
'Outgoing HTTP URL: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'tcp', // proto
|
||||
'$HOME_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$EXTERNAL_NET', // dst_ip
|
||||
'$HTTP_PORTS', // dst_port
|
||||
'Outgoing HTTP URL: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -495,17 +646,17 @@ class NidsExport
|
|||
$this->rules[] = sprintf(
|
||||
$ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
|
||||
'tcp', // proto
|
||||
'$HOME_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$EXTERNAL_NET', // dst_ip
|
||||
'$HTTP_PORTS', // dst_port
|
||||
'Outgoing User-Agent: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
'tcp', // proto
|
||||
'$HOME_NET', // src_ip
|
||||
'any', // src_port
|
||||
'->', // direction
|
||||
'$EXTERNAL_NET', // dst_ip
|
||||
'$HTTP_PORTS', // dst_port
|
||||
'Outgoing User-Agent: ' . $attribute['value'], // msg
|
||||
$content, // rule_content
|
||||
'tag:session,600,seconds;', // tag
|
||||
$sid, // sid
|
||||
1 // rev
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -527,37 +678,37 @@ class NidsExport
|
|||
$tmpRule = str_replace(array("\r","\n"), " ", $attribute['value']);
|
||||
|
||||
// rebuild the rule by overwriting the different keywords using preg_replace()
|
||||
// sid - '/sid\s*:\s*[0-9]+\s*;/'
|
||||
// rev - '/rev\s*:\s*[0-9]+\s*;/'
|
||||
// sid - '/sid\s*:\s*[0-9]+\s*;/'
|
||||
// rev - '/rev\s*:\s*[0-9]+\s*;/'
|
||||
// classtype - '/classtype:[a-zA-Z_-]+;/'
|
||||
// msg - '/msg\s*:\s*".*?"\s*;/'
|
||||
// msg - '/msg\s*:\s*".*?"\s*;/'
|
||||
// reference - '/reference\s*:\s*.+?;/'
|
||||
// tag - '/tag\s*:\s*.+?;/'
|
||||
// tag - '/tag\s*:\s*.+?;/'
|
||||
$replaceCount = array();
|
||||
$tmpRule = preg_replace('/sid\s*:\s*[0-9]+\s*;/', 'sid:' . $sid . ';', $tmpRule, -1, $replaceCount['sid']);
|
||||
if (null == $tmpRule) {
|
||||
return false;
|
||||
} // don't output the rule on error with the regex
|
||||
} // don't output the rule on error with the regex
|
||||
$tmpRule = preg_replace('/rev\s*:\s*[0-9]+\s*;/', 'rev:1;', $tmpRule, -1, $replaceCount['rev']);
|
||||
if (null == $tmpRule) {
|
||||
return false;
|
||||
} // don't output the rule on error with the regex
|
||||
} // don't output the rule on error with the regex
|
||||
$tmpRule = preg_replace('/classtype:[a-zA-Z_-]+;/', 'classtype:' . $this->classtype . ';', $tmpRule, -1, $replaceCount['classtype']);
|
||||
if (null == $tmpRule) {
|
||||
return false;
|
||||
} // don't output the rule on error with the regex
|
||||
} // don't output the rule on error with the regex
|
||||
$tmpRule = preg_replace('/msg\s*:\s*"(.*?)"\s*;/', sprintf($ruleFormatMsg, 'snort-rule | $1') . ';', $tmpRule, -1, $replaceCount['msg']);
|
||||
if (null == $tmpRule) {
|
||||
return false;
|
||||
} // don't output the rule on error with the regex
|
||||
} // don't output the rule on error with the regex
|
||||
$tmpRule = preg_replace('/reference\s*:\s*.+?;/', $ruleFormatReference . ';', $tmpRule, -1, $replaceCount['reference']);
|
||||
if (null == $tmpRule) {
|
||||
return false;
|
||||
} // don't output the rule on error with the regex
|
||||
} // don't output the rule on error with the regex
|
||||
$tmpRule = preg_replace('/reference\s*:\s*.+?;/', $ruleFormatReference . ';', $tmpRule, -1, $replaceCount['reference']);
|
||||
if (null == $tmpRule) {
|
||||
return false;
|
||||
} // don't output the rule on error with the regex
|
||||
} // don't output the rule on error with the regex
|
||||
// FIXME nids - implement priority overwriting
|
||||
|
||||
// some values were not replaced, so we need to add them ourselves, and insert them in the rule
|
||||
|
@ -667,13 +818,13 @@ class NidsExport
|
|||
|
||||
public function checkWhitelist($value)
|
||||
{
|
||||
if ($this->checkWhitelist && is_array($this->whitelist)) {
|
||||
foreach ($this->whitelist as $wlitem) {
|
||||
if (preg_match($wlitem, $value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->checkWhitelist && is_array($this->whitelist)) {
|
||||
foreach ($this->whitelist as $wlitem) {
|
||||
if (preg_match($wlitem, $value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -717,4 +868,4 @@ class NidsExport
|
|||
}
|
||||
return $ipport;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
class BetterCakeEventManager extends CakeEventManager
|
||||
{
|
||||
/**
|
||||
* This method is similar as original dispatch, but do not return newly created event. With returning event, there is
|
||||
* big memory leak in PHP at least for PHP version 7.4.19.
|
||||
* @param CakeEvent $event
|
||||
*/
|
||||
public function dispatch($event)
|
||||
{
|
||||
$listeners = $this->listeners($event->name());
|
||||
if (empty($listeners)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ($listeners as $listener) {
|
||||
if ($event->isStopped()) {
|
||||
break;
|
||||
}
|
||||
if ($listener['passParams'] === true) {
|
||||
$result = call_user_func_array($listener['callable'], $event->data);
|
||||
} else {
|
||||
$result = $listener['callable']($event);
|
||||
}
|
||||
if ($result === false) {
|
||||
$event->stopPropagation();
|
||||
}
|
||||
if ($result !== null) {
|
||||
$event->result = $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $eventKey
|
||||
* @return array
|
||||
*/
|
||||
public function listeners($eventKey)
|
||||
{
|
||||
if ($this->_isGlobal) {
|
||||
$localListeners = [];
|
||||
} else {
|
||||
$localListeners = $this->_listeners[$eventKey] ?? [];
|
||||
}
|
||||
|
||||
$globalListeners = static::instance()->prioritisedListeners($eventKey);
|
||||
|
||||
$priorities = array_merge(array_keys($globalListeners), array_keys($localListeners));
|
||||
$priorities = array_unique($priorities, SORT_REGULAR);
|
||||
asort($priorities);
|
||||
|
||||
$result = [];
|
||||
foreach ($priorities as $priority) {
|
||||
if (isset($globalListeners[$priority])) {
|
||||
$result = array_merge($result, $globalListeners[$priority]);
|
||||
}
|
||||
if (isset($localListeners[$priority])) {
|
||||
$result = array_merge($result, $localListeners[$priority]);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -484,6 +484,10 @@ class SendEmail
|
|||
]);
|
||||
}
|
||||
|
||||
if ($body instanceof SendEmailTemplate && $body->listUnsubscribe()) {
|
||||
$email->addHeaders(['List-Unsubscribe' => "<{$body->listUnsubscribe()}>"]);
|
||||
}
|
||||
|
||||
$signed = false;
|
||||
if (Configure::read('GnuPG.sign')) {
|
||||
if (!$this->gpg) {
|
||||
|
|
|
@ -10,6 +10,9 @@ class SendEmailTemplate
|
|||
/** @var string|null */
|
||||
private $referenceId;
|
||||
|
||||
/** @var string */
|
||||
private $listUnsubscribe;
|
||||
|
||||
/** @var string|null */
|
||||
private $subject;
|
||||
|
||||
|
@ -31,6 +34,18 @@ class SendEmailTemplate
|
|||
$this->referenceId = $referenceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $listUnsubscribe
|
||||
* @return string|void
|
||||
*/
|
||||
public function listUnsubscribe($listUnsubscribe = null)
|
||||
{
|
||||
if ($listUnsubscribe === null) {
|
||||
return $this->listUnsubscribe;
|
||||
}
|
||||
$this->listUnsubscribe = $listUnsubscribe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get subject from template. Must be called after render method.
|
||||
* @param string|null $subject
|
||||
|
|
|
@ -25,6 +25,7 @@ App::uses('LogableBehavior', 'Assets.models/behaviors');
|
|||
App::uses('RandomTool', 'Tools');
|
||||
App::uses('FileAccessTool', 'Tools');
|
||||
App::uses('JsonTool', 'Tools');
|
||||
App::uses('BetterCakeEventManager', 'Tools');
|
||||
|
||||
class AppModel extends Model
|
||||
{
|
||||
|
@ -47,15 +48,6 @@ class AppModel extends Model
|
|||
/** @var AttachmentTool|null */
|
||||
private $attachmentTool;
|
||||
|
||||
public function __construct($id = false, $table = null, $ds = null)
|
||||
{
|
||||
parent::__construct($id, $table, $ds);
|
||||
$this->findMethods['column'] = true;
|
||||
if (in_array('phar', stream_get_wrappers())) {
|
||||
stream_wrapper_unregister('phar');
|
||||
}
|
||||
}
|
||||
|
||||
// deprecated, use $db_changes
|
||||
// major -> minor -> hotfix -> requires_logout
|
||||
const OLD_DB_CHANGES = array(
|
||||
|
@ -93,7 +85,7 @@ class AppModel extends Model
|
|||
87,
|
||||
);
|
||||
|
||||
public $advanced_updates_description = array(
|
||||
const ADVANCED_UPDATES_DESCRIPTION = array(
|
||||
'seenOnAttributeAndObject' => array(
|
||||
'title' => 'First seen/Last seen Attribute table',
|
||||
'description' => 'Update the Attribute table to support first_seen and last_seen feature, with a microsecond resolution.',
|
||||
|
@ -107,6 +99,15 @@ class AppModel extends Model
|
|||
),
|
||||
);
|
||||
|
||||
public function __construct($id = false, $table = null, $ds = null)
|
||||
{
|
||||
parent::__construct($id, $table, $ds);
|
||||
$this->findMethods['column'] = true;
|
||||
if (in_array('phar', stream_get_wrappers(), true)) {
|
||||
stream_wrapper_unregister('phar');
|
||||
}
|
||||
}
|
||||
|
||||
public function isAcceptedDatabaseError($errorMessage)
|
||||
{
|
||||
if ($this->isMysql()) {
|
||||
|
@ -275,9 +276,9 @@ class AppModel extends Model
|
|||
|
||||
$liveOff = false;
|
||||
$exitOnError = false;
|
||||
if (isset($this->advanced_updates_description[$command])) {
|
||||
$liveOff = isset($this->advanced_updates_description[$command]['liveOff']) ? $this->advanced_updates_description[$command]['liveOff'] : $liveOff;
|
||||
$exitOnError = isset($this->advanced_updates_description[$command]['exitOnError']) ? $this->advanced_updates_description[$command]['exitOnError'] : $exitOnError;
|
||||
if (isset(self::ADVANCED_UPDATES_DESCRIPTION[$command])) {
|
||||
$liveOff = isset(self::ADVANCED_UPDATES_DESCRIPTION[$command]['liveOff']) ? self::ADVANCED_UPDATES_DESCRIPTION[$command]['liveOff'] : $liveOff;
|
||||
$exitOnError = isset(self::ADVANCED_UPDATES_DESCRIPTION[$command]['exitOnError']) ? self::ADVANCED_UPDATES_DESCRIPTION[$command]['exitOnError'] : $exitOnError;
|
||||
}
|
||||
|
||||
$sqlArray = array();
|
||||
|
@ -1798,7 +1799,7 @@ class AppModel extends Model
|
|||
$total_update_count = $sql_update_count + $index_update_count;
|
||||
$this->__setUpdateProgress(0, $total_update_count, $command);
|
||||
$str_index_array = array();
|
||||
foreach($indexArray as $toIndex) {
|
||||
foreach ($indexArray as $toIndex) {
|
||||
$str_index_array[] = __('Indexing %s -> %s', $toIndex[0], $toIndex[1]);
|
||||
}
|
||||
$this->__setUpdateCmdMessages(array_merge($sqlArray, $str_index_array));
|
||||
|
@ -1806,8 +1807,8 @@ class AppModel extends Model
|
|||
$errorCount = 0;
|
||||
|
||||
// execute test before update. Exit if it fails
|
||||
if (isset($this->advanced_updates_description[$command]['preUpdate'])) {
|
||||
$function_name = $this->advanced_updates_description[$command]['preUpdate'];
|
||||
if (isset(self::ADVANCED_UPDATES_DESCRIPTION[$command]['preUpdate'])) {
|
||||
$function_name = self::ADVANCED_UPDATES_DESCRIPTION[$command]['preUpdate'];
|
||||
try {
|
||||
$this->{$function_name}();
|
||||
} catch (Exception $e) {
|
||||
|
@ -1943,10 +1944,15 @@ class AppModel extends Model
|
|||
$this->Server->serverSettingsSaveValue('MISP.live', $isLive);
|
||||
}
|
||||
|
||||
// check whether the adminSetting should be updated after the update
|
||||
private function __postUpdate($command) {
|
||||
if (isset($this->advanced_updates_description[$command]['record'])) {
|
||||
if($this->advanced_updates_description[$command]['record']) {
|
||||
/**
|
||||
* Check whether the adminSetting should be updated after the update.
|
||||
* @param string $command
|
||||
* @return void
|
||||
*/
|
||||
private function __postUpdate($command)
|
||||
{
|
||||
if (isset(self::ADVANCED_UPDATES_DESCRIPTION[$command]['record'])) {
|
||||
if (self::ADVANCED_UPDATES_DESCRIPTION[$command]['record']) {
|
||||
$this->AdminSetting->changeSetting($command, 1);
|
||||
}
|
||||
}
|
||||
|
@ -3457,4 +3463,19 @@ class AppModel extends Model
|
|||
$logEntries[] = $logEntry;
|
||||
Configure::write('pendingLogEntries', $logEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use different CakeEventManager to fix memory leak
|
||||
* @return CakeEventManager
|
||||
*/
|
||||
public function getEventManager()
|
||||
{
|
||||
if (empty($this->_eventManager)) {
|
||||
$this->_eventManager = new BetterCakeEventManager();
|
||||
$this->_eventManager->attach($this->Behaviors);
|
||||
$this->_eventManager->attach($this);
|
||||
}
|
||||
|
||||
return $this->_eventManager;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1734,8 +1734,13 @@ class Attribute extends AppModel
|
|||
return $result;
|
||||
}
|
||||
|
||||
// This method takes a string from an argument with several elements (separated by '&&' and negated by '!') and returns 2 arrays
|
||||
// array 1 will have all of the non negated terms and array 2 all the negated terms
|
||||
/**
|
||||
* This method takes a string from an argument with several elements (separated by '&&' and negated by '!') and returns 2 arrays
|
||||
* array 1 will have all of the non negated terms and array 2 all the negated terms
|
||||
*
|
||||
* @param string|array $args
|
||||
* @return array[]
|
||||
*/
|
||||
public function dissectArgs($args)
|
||||
{
|
||||
$result = array(0 => array(), 1 => array(), 2 => array());
|
||||
|
@ -1757,7 +1762,7 @@ class Attribute extends AppModel
|
|||
}
|
||||
} else {
|
||||
foreach ($args as $arg) {
|
||||
if ($arg[0] === '!') {
|
||||
if (is_string($arg) && $arg[0] === '!') {
|
||||
$result[1][] = substr($arg, 1);
|
||||
} else {
|
||||
$result[0][] = $arg;
|
||||
|
@ -2476,7 +2481,7 @@ class Attribute extends AppModel
|
|||
}
|
||||
$temp = $this->Event->EventTag->find('all', array(
|
||||
'recursive' => -1,
|
||||
'contain' => array('Tag'),
|
||||
'contain' => ['Tag' => ['fields' => ['id', 'name', 'colour', 'numerical_value']]],
|
||||
'conditions' => $tagConditions,
|
||||
));
|
||||
if (empty($temp)) {
|
||||
|
@ -2484,16 +2489,11 @@ class Attribute extends AppModel
|
|||
} else {
|
||||
foreach ($temp as $tag) {
|
||||
$tag['EventTag']['Tag'] = $tag['Tag'];
|
||||
unset($tag['Tag']);
|
||||
$eventTags[$eventId][] = $tag['EventTag'];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($eventTags)) {
|
||||
foreach ($eventTags[$eventId] as $eventTag) {
|
||||
$attribute['EventTag'][] = $eventTag;
|
||||
}
|
||||
}
|
||||
$attribute['EventTag'] = $eventTags[$eventId];
|
||||
return $attribute;
|
||||
}
|
||||
|
||||
|
@ -2690,8 +2690,12 @@ class Attribute extends AppModel
|
|||
public function setTimestampConditions($timestamp, $conditions, $scope = 'Event.timestamp', $returnRaw = false)
|
||||
{
|
||||
if (is_array($timestamp)) {
|
||||
$timestamp[0] = intval($this->Event->resolveTimeDelta($timestamp[0]));
|
||||
$timestamp[1] = intval($this->Event->resolveTimeDelta($timestamp[1]));
|
||||
if (count($timestamp) !== 2) {
|
||||
throw new InvalidArgumentException('Invalid date specification, must be string or array with two elements');
|
||||
}
|
||||
|
||||
$timestamp[0] = intval($this->resolveTimeDelta($timestamp[0]));
|
||||
$timestamp[1] = intval($this->resolveTimeDelta($timestamp[1]));
|
||||
if ($timestamp[0] > $timestamp[1]) {
|
||||
$temp = $timestamp[0];
|
||||
$timestamp[0] = $timestamp[1];
|
||||
|
@ -2700,7 +2704,7 @@ class Attribute extends AppModel
|
|||
$conditions['AND'][] = array($scope . ' >=' => $timestamp[0]);
|
||||
$conditions['AND'][] = array($scope . ' <=' => $timestamp[1]);
|
||||
} else {
|
||||
$timestamp = intval($this->Event->resolveTimeDelta($timestamp));
|
||||
$timestamp = intval($this->resolveTimeDelta($timestamp));
|
||||
$conditions['AND'][] = array($scope . ' >=' => $timestamp);
|
||||
}
|
||||
if ($returnRaw) {
|
||||
|
@ -2712,8 +2716,8 @@ class Attribute extends AppModel
|
|||
public function setTimestampSeenConditions($timestamp, $conditions, $scope = 'Attribute.first_seen', $returnRaw = false)
|
||||
{
|
||||
if (is_array($timestamp)) {
|
||||
$timestamp[0] = intval($this->Event->resolveTimeDelta($timestamp[0])) * 1000000; // seen in stored in micro-seconds in the DB
|
||||
$timestamp[1] = intval($this->Event->resolveTimeDelta($timestamp[1])) * 1000000; // seen in stored in micro-seconds in the DB
|
||||
$timestamp[0] = intval($this->resolveTimeDelta($timestamp[0])) * 1000000; // seen in stored in micro-seconds in the DB
|
||||
$timestamp[1] = intval($this->resolveTimeDelta($timestamp[1])) * 1000000; // seen in stored in micro-seconds in the DB
|
||||
if ($timestamp[0] > $timestamp[1]) {
|
||||
$temp = $timestamp[0];
|
||||
$timestamp[0] = $timestamp[1];
|
||||
|
@ -2722,7 +2726,7 @@ class Attribute extends AppModel
|
|||
$conditions['AND'][] = array($scope . ' >=' => $timestamp[0]);
|
||||
$conditions['AND'][] = array($scope . ' <=' => $timestamp[1]);
|
||||
} else {
|
||||
$timestamp = intval($this->Event->resolveTimeDelta($timestamp)) * 1000000; // seen in stored in micro-seconds in the DB
|
||||
$timestamp = intval($this->resolveTimeDelta($timestamp)) * 1000000; // seen in stored in micro-seconds in the DB
|
||||
if ($scope == 'Attribute.first_seen') {
|
||||
$conditions['AND'][] = array($scope . ' >=' => $timestamp);
|
||||
} else {
|
||||
|
|
|
@ -769,7 +769,7 @@ class Event extends AppModel
|
|||
}
|
||||
|
||||
$correlations = array_column($correlations, $correlationModelName);
|
||||
$eventIds = array_unique(array_column($correlations, 'event_id'));
|
||||
$eventIds = array_unique(array_column($correlations, 'event_id'), SORT_REGULAR);
|
||||
|
||||
$conditions = $this->createEventConditions($user);
|
||||
$conditions['Event.id'] = $eventIds;
|
||||
|
@ -2753,7 +2753,7 @@ class Event extends AppModel
|
|||
|
||||
public function set_filter_published(&$params, $conditions, $options)
|
||||
{
|
||||
if (isset($params['published'])) {
|
||||
if (isset($params['published']) && $params['published'] !== [true, false]) {
|
||||
$conditions['AND']['Event.published'] = $params['published'];
|
||||
}
|
||||
return $conditions;
|
||||
|
@ -3131,8 +3131,8 @@ class Event extends AppModel
|
|||
{
|
||||
if (Configure::read('MISP.extended_alert_subject')) {
|
||||
$subject = preg_replace("/\r|\n/", "", $event['Event']['info']);
|
||||
if (strlen($subject) > 58) {
|
||||
$subject = substr($subject, 0, 55) . '... - ';
|
||||
if (mb_strlen($subject) > 58) {
|
||||
$subject = mb_substr($subject, 0, 55) . '... - ';
|
||||
} else {
|
||||
$subject .= " - ";
|
||||
}
|
||||
|
@ -3159,6 +3159,10 @@ class Event extends AppModel
|
|||
$template->set('tlp', $subjMarkingString);
|
||||
$template->subject($subject);
|
||||
$template->referenceId("event-alert|{$event['Event']['id']}");
|
||||
|
||||
$unsubscribeLink = $this->__getAnnounceBaseurl() . '/users/unsubscribe/' . $this->User->unsubscribeCode($user);
|
||||
$template->set('unsubscribe', $unsubscribeLink);
|
||||
$template->listUnsubscribe($unsubscribeLink);
|
||||
return $template;
|
||||
}
|
||||
|
||||
|
|
|
@ -1124,7 +1124,7 @@ class GalaxyCluster extends AppModel
|
|||
|
||||
if (!empty($tagsToFetch)) {
|
||||
$tags = $this->GalaxyClusterRelation->GalaxyClusterRelationTag->Tag->find('all', [
|
||||
'conditions' => ['id' => array_unique($tagsToFetch)],
|
||||
'conditions' => ['id' => array_unique($tagsToFetch, SORT_REGULAR)],
|
||||
'recursive' => -1,
|
||||
]);
|
||||
$tags = array_column(array_column($tags, 'Tag'), null, 'id');
|
||||
|
|
|
@ -205,7 +205,7 @@ class Log extends AppModel
|
|||
*/
|
||||
public function createLogEntry($user, $action, $model, $modelId = 0, $title = '', $change = '')
|
||||
{
|
||||
if (in_array($action, ['tag', 'galaxy', 'publish', 'publish_sightings', 'enable'], true) && Configure::read('MISP.log_new_audit')) {
|
||||
if (in_array($action, ['tag', 'galaxy', 'publish', 'publish_sightings', 'enable', 'edit'], true) && Configure::read('MISP.log_new_audit')) {
|
||||
return; // Do not store tag changes when new audit is enabled
|
||||
}
|
||||
if ($user === 'SYSTEM') {
|
||||
|
|
|
@ -1613,4 +1613,14 @@ class User extends AppModel
|
|||
'conditions' => array('EventDelegation.org_id' => $user['org_id'])
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate code that is used in event alert unsubscribe link.
|
||||
* @return string
|
||||
*/
|
||||
public function unsubscribeCode(array $user)
|
||||
{
|
||||
$salt = Configure::read('Security.salt');
|
||||
return substr(hash('sha256', "{$user['id']}|$salt"), 0, 8);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ if (!isset($contactAlert)) {
|
|||
if ($hideDetails) { // Used when GnuPG.bodyonlyencrypted is enabled and e-mail cannot be send in encrypted form
|
||||
$eventUrl = $baseurl . "/events/view/" . $event['Event']['id'];
|
||||
echo __("A new or modified event was just published on %s", $eventUrl) . PHP_EOL . PHP_EOL;
|
||||
echo __("If you would like to unsubscribe from receiving such alert e-mails, simply\ndisable publish alerts via %s", $baseurl . '/users/edit');
|
||||
echo __("If you would like to unsubscribe from receiving such alert e-mails, simply\ndisable publish alerts via %s", $unsubscribe);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -112,5 +112,5 @@ You receive this e-mail because the e-mail address <?= $user['email'] ?> is set
|
|||
to receive <?= $contactAlert ? 'contact' : 'publish' ?> alerts on the MISP instance at <?= $baseurl ?>.
|
||||
|
||||
If you would like to unsubscribe from receiving such alert e-mails, simply
|
||||
disable <?= $contactAlert ? 'contact' : 'publish' ?> alerts via <?= $baseurl ?>/users/edit
|
||||
disable <?= $contactAlert ? 'contact' : 'publish' ?> alerts via <?= $unsubscribe ?>.
|
||||
==============================================
|
||||
|
|
|
@ -11,7 +11,7 @@ echo $this->element('genericElements/Form/genericForm', [
|
|||
'class' => 'input span6',
|
||||
'div' => 'input clear',
|
||||
'type' => 'select',
|
||||
'options' => array_combine($exportFormats, $exportFormats),
|
||||
'options' => $exportFormats,
|
||||
],
|
||||
],
|
||||
'submit' => [
|
||||
|
|
|
@ -4831,7 +4831,9 @@ $(document.body).on('click', 'a[data-paginator]', function (e) {
|
|||
xhr({
|
||||
dataType: "html",
|
||||
success: function (data) {
|
||||
$(paginatorTarget).html(data);
|
||||
var $target = $(paginatorTarget);
|
||||
destroyPopovers($target);
|
||||
$target.html(data);
|
||||
},
|
||||
url: $(this).attr('href'),
|
||||
});
|
||||
|
@ -4849,6 +4851,12 @@ $(document.body).on('click', '[data-popover-popup]', function (e) {
|
|||
popoverPopupNew(this, url);
|
||||
});
|
||||
|
||||
function destroyPopovers($element) {
|
||||
$element.find('[data-dismissid]').each(function() {
|
||||
$(this).popover('destroy');
|
||||
});
|
||||
}
|
||||
|
||||
function queryEventLock(event_id, timestamp) {
|
||||
var interval = null;
|
||||
var errorCount = 0;
|
||||
|
|
|
@ -797,6 +797,24 @@ class TestComprehensive(unittest.TestCase):
|
|||
self.assertTrue(created_user.autoalert, created_user)
|
||||
self.admin_misp_connector.delete_user(created_user)
|
||||
|
||||
def test_search_snort_suricata(self):
|
||||
event = create_simple_event()
|
||||
event.add_attribute('ip-src', '8.8.8.8', to_ids=True)
|
||||
event = self.user_misp_connector.add_event(event)
|
||||
check_response(event)
|
||||
|
||||
self.admin_misp_connector.publish(event, alert=False)
|
||||
|
||||
snort = self._search({'returnFormat': 'snort', 'eventid': event.id})
|
||||
self.assertIsInstance(snort, str)
|
||||
self.assertIn('8.8.8.8', snort)
|
||||
|
||||
suricata = self._search({'returnFormat': 'suricata', 'eventid': event.id})
|
||||
self.assertIsInstance(suricata, str)
|
||||
self.assertIn('8.8.8.8', suricata)
|
||||
|
||||
self.admin_misp_connector.delete_event(event)
|
||||
|
||||
def _search(self, query: dict):
|
||||
response = self.admin_misp_connector._prepare_request('POST', 'events/restSearch', data=query)
|
||||
response = self.admin_misp_connector._check_response(response)
|
||||
|
|
Loading…
Reference in New Issue