Merge pull request #1 from Benni0/develop

Merge fix for workflow:module_splunk_hec_export
pull/8835/head
Benni0 2023-03-02 10:04:36 +01:00 committed by GitHub
commit f99828ba8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 496 additions and 277 deletions

2
PyMISP

@ -1 +1 @@
Subproject commit cca5287b2b11a1951789680c75e10636dde98add
Subproject commit 9a7adb2e0d60d2edee9f541db808652875bae20e

View File

@ -41,7 +41,7 @@ The objective of MISP is to foster the sharing of structured information within
MISP, Malware Information Sharing Platform and Threat Sharing, core functionalities are:
- An **efficient IOC and indicators** database allowing to store technical and non-technical information about malware samples, incidents, attackers and intelligence.
- An **efficient IOC and indicators** database, allowing to store technical and non-technical information about malware samples, incidents, attackers and intelligence.
- Automatic **correlation** finding relationships between attributes and indicators from malware, attack campaigns or analysis. The correlation engine includes correlation between attributes and more advanced correlations like Fuzzy hashing correlation (e.g. ssdeep) or CIDR block matching. Correlation can also be enabled or event disabled per attribute.
- A **flexible data model** where complex [objects](https://www.misp-project.org/objects.html) can be expressed and **linked together to express threat intelligence, incidents or connected elements**.
- Built-in **sharing functionality** to ease data sharing using different model of distributions. MISP can automatically synchronize events and attributes among different MISP instances. Advanced filtering functionalities can be used to meet each organization's sharing policy including a **flexible sharing group** capacity and an attribute level distribution mechanisms.
@ -50,9 +50,9 @@ MISP, Malware Information Sharing Platform and Threat Sharing, core functionalit
- **export**: generating IDS, OpenIOC, plain text, CSV, MISP XML or JSON output to integrate with other systems (network IDS, host IDS, custom tools), Cache format (used for forensic tools), STIX (XML and JSON) 1 and 2, NIDS export (Suricata, Snort and Bro/Zeek) or RPZ zone. Many other formats can be easily added via the [misp-modules](https://github.com/MISP/misp-modules).
- **import**: bulk-import, batch-import, import from OpenIOC, GFI sandbox, ThreatConnect CSV, MISP standard format or STIX 1.1/2.0. Many other formats easily added via the [misp-modules](https://github.com/MISP/misp-modules).
- Flexible **free text import** tool to ease the integration of unstructured reports into MISP.
- A gentle system to **collaborate** on events and attributes allowing MISP users to propose changes or updates to attributes/indicators.
- A user-friendly system to **collaborate** on events and attributes allowing MISP users to propose changes or updates to attributes/indicators.
- **data-sharing**: automatically exchange and synchronize with other parties and trust-groups using MISP.
- **delegating of sharing**: allows a simple pseudo-anonymous mechanism to delegate publication of event/indicators to another organization.
- **delegating of sharing**: allows for a simple, pseudo-anonymous mechanism to delegate publication of event/indicators to another organization.
- Flexible **API** to integrate MISP with your own solutions. MISP is bundled with [PyMISP](https://github.com/MISP/PyMISP) which is a flexible Python Library to fetch, add or update events attributes, handle malware samples or search for attributes. An exhaustive restSearch API to easily search for indicators in MISP and exports those in all the format supported by MISP.
- **Adjustable taxonomy** to classify and tag events following your own classification schemes or [existing classification](https://github.com/MISP/misp-taxonomies). The taxonomy can be local to your MISP but also shareable among MISP instances.
- **Intelligence vocabularies** called MISP galaxy and bundled with existing [threat actors, malware, RAT, ransomware or MITRE ATT&CK](https://www.misp-project.org/galaxy.html) which can be easily linked with events and attributes in MISP.
@ -108,16 +108,16 @@ License
This software is licensed under [GNU Affero General Public License version 3](http://www.gnu.org/licenses/agpl-3.0.html)
* Copyright (C) 2012-2022 Christophe Vandeplas
* Copyright (C) 2012-2023 Christophe Vandeplas
* Copyright (C) 2012 Belgian Defence
* Copyright (C) 2012 NATO / NCIRC
* Copyright (C) 2013-2022 Andras Iklody
* Copyright (C) 2015-2022 CIRCL - Computer Incident Response Center Luxembourg
* Copyright (C) 2013-2023 Andras Iklody
* Copyright (C) 2015-2023 CIRCL - Computer Incident Response Center Luxembourg
* Copyright (C) 2016 Andreas Ziegler
* Copyright (C) 2018-2022 Sami Mokaddem
* Copyright (C) 2018-2022 Christian Studer
* Copyright (C) 2015-2022 Alexandre Dulaunoy
* Copyright (C) 2018-2023 Sami Mokaddem
* Copyright (C) 2018-2023 Christian Studer
* Copyright (C) 2015-2023 Alexandre Dulaunoy
* Copyright (C) 2018-2022 Steve Clement
* Copyright (C) 2020-2022 Jakub Onderka
* Copyright (C) 2020-2023 Jakub Onderka
For more information, [the list of authors and contributors](AUTHORS) is available.

View File

@ -1 +1 @@
{"major":2, "minor":4, "hotfix":167}
{"major":2, "minor":4, "hotfix":168}

View File

@ -33,8 +33,8 @@ class AppController extends Controller
public $helpers = array('OrgImg', 'FontAwesome', 'UserName');
private $__queryVersion = '146';
public $pyMispVersion = '2.4.167';
private $__queryVersion = '147';
public $pyMispVersion = '2.4.168';
public $phpmin = '7.2';
public $phprec = '7.4';
public $phptoonew = '8.0';
@ -152,20 +152,25 @@ class AppController extends Controller
}
$this->User = ClassRegistry::init('User');
if ($this->Auth->user()) {
if ($this->User->checkForSessionDestruction($this->Auth->user('id'))) {
$this->Auth->logout();
$this->Session->destroy();
$message = __('User deauthenticated on administrator request. Please reauthenticate.');
if ($this->_isRest()) {
throw new ForbiddenException($message);
} else {
$this->Flash->warning($message);
$this->_redirectToLogin();
}
}
if (!empty($this->request->params['named']['disable_background_processing'])) {
Configure::write('MISP.background_jobs', 0);
}
Configure::write('CurrentController', $controller);
Configure::write('CurrentAction', $action);
$versionArray = $this->User->checkMISPVersion();
$this->mispVersion = implode('.', $versionArray);
$this->Security->blackHoleCallback = 'blackHole';
// send users away that are using ancient versions of IE
// Make sure to update this if IE 20 comes out :)
if (isset($_SERVER['HTTP_USER_AGENT'])) {
if (preg_match('/(?i)msie [2-8]/', $_SERVER['HTTP_USER_AGENT']) && !strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
throw new MethodNotAllowedException('You are using an unsecure and outdated version of IE, please download Google Chrome, Mozilla Firefox or update to a newer version of IE. If you are running IE9 or newer and still receive this error message, please make sure that you are not running your browser in compatibility mode. If you still have issues accessing the site, get in touch with your administration team at ' . Configure::read('MISP.contact'));
}
}
// For fresh installation (salt empty) generate a new salt
if (!Configure::read('Security.salt')) {
$this->User->Server->serverSettingsSaveValue('Security.salt', $this->User->generateRandomPassword(32));
@ -176,6 +181,10 @@ class AppController extends Controller
$this->User->Server->serverSettingsSaveValue('MISP.uuid', CakeText::uuid());
}
/**
* Authentication related activities
*/
// Check if Apache provides kerberos authentication data
$authUserFields = $this->User->describeAuthFields();
$envvar = Configure::read('ApacheSecureAuth.apacheEnv');
@ -191,22 +200,7 @@ class AppController extends Controller
} else {
$this->Auth->authenticate[AuthComponent::ALL]['userFields'] = $authUserFields;
}
if (!empty($this->request->params['named']['disable_background_processing'])) {
Configure::write('MISP.background_jobs', 0);
}
Configure::write('CurrentController', $controller);
Configure::write('CurrentAction', $action);
$versionArray = $this->User->checkMISPVersion();
$this->mispVersion = implode('.', $versionArray);
$this->Security->blackHoleCallback = 'blackHole';
// send users away that are using ancient versions of IE
// Make sure to update this if IE 20 comes out :)
if (isset($_SERVER['HTTP_USER_AGENT'])) {
if (preg_match('/(?i)msie [2-8]/', $_SERVER['HTTP_USER_AGENT']) && !strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
throw new MethodNotAllowedException('You are using an unsecure and outdated version of IE, please download Google Chrome, Mozilla Firefox or update to a newer version of IE. If you are running IE9 or newer and still receive this error message, please make sure that you are not running your browser in compatibility mode. If you still have issues accessing the site, get in touch with your administration team at ' . Configure::read('MISP.contact'));
}
}
$userLoggedIn = false;
if (Configure::read('Plugin.CustomAuth_enable')) {
$userLoggedIn = $this->__customAuthentication($_SERVER);
@ -528,12 +522,24 @@ class AppController extends Controller
}
$this->Flash->info($message);
$this->Auth->logout();
throw new MethodNotAllowedException($message);//todo this should pb be removed?
$this->_redirectToLogin();
return false;
} else {
$this->Flash->error(__('Warning: MISP is currently disabled for all users. Enable it in Server Settings (Administration -> Server Settings -> MISP tab -> live). An update might also be in progress, you can see the progress in ') , array('params' => array('url' => $this->baseurl . '/servers/updateProgress/', 'urlName' => __('Update Progress')), 'clear' => 1));
}
}
// kill existing sessions for a user if the admin/instance decides so
// exclude API authentication as it doesn't make sense
if (!$this->isApiAuthed && $this->User->checkForSessionDestruction($user['id'])) {
$this->Auth->logout();
$this->Session->destroy();
$message = __('User deauthenticated on administrator request. Please reauthenticate.');
$this->Flash->warning($message);
$this->_redirectToLogin();
return false;
}
// Force logout doesn't make sense for API key authentication
if (!$this->isApiAuthed && $user['force_logout']) {
$this->User->id = $user['id'];

View File

@ -192,10 +192,13 @@ class AuditLogsController extends AppController
$list[$k]['AuditLog']['action_human'] = $this->actions[$item['AuditLog']['action']];
}
$this->set('list', $list);
$this->set('data', $list);
$this->set('event', $event);
$this->set('mayModify', $this->__canModifyEvent($event));
$this->set('title_for_layout', __('Audit logs for event #%s', $event['Event']['id']));
$this->set('menuData', [
'menuList' => 'event',
'menuItem' => 'eventLog'
]);
}
public function fullChange($id)

View File

@ -125,7 +125,7 @@ class ACLComponent extends Component
'decayingModel' => array(
"update" => array(),
"export" => array('*'),
"import" => array('*'),
"import" => array('OR' => array('perm_admin', 'perm_decaying')),
"view" => array('*'),
"index" => array('*'),
"add" => array( 'OR' => array('perm_admin', 'perm_decaying')),

View File

@ -114,7 +114,7 @@ class CRUDComponent extends Component
$this->Controller->Flash->success($message);
if (!empty($params['displayOnSuccess'])) {
$this->Controller->set('entity', $data);
$this->Controller->set('referer', $this->Controller->referer());
$this->Controller->set('referer', $this->Controller->referer(['action' => 'view', $model->id], true));
$this->Controller->render($params['displayOnSuccess']);
return;
}

View File

@ -183,9 +183,9 @@ class DashboardsController extends AppController
} else {
$data = $dashboardWidget->handler($user, $valueConfig);
}
$renderer = method_exists($dashboardWidget, 'getRenderer') ? $dashboardWidget->getRenderer($valueConfig) : $dashboardWidget->render;
$config = array(
'render' => $dashboardWidget->render,
'render' => $renderer,
'autoRefreshDelay' => empty($dashboardWidget->autoRefreshDelay) ? false : $dashboardWidget->autoRefreshDelay,
'widget_config' => empty($valueConfig['widget_config']) ? array() : $valueConfig['widget_config']
);

View File

@ -2324,6 +2324,9 @@ class EventsController extends AppController
if ($this->request->is('post')) {
$results = array();
if (!empty($this->request->data)) {
if (empty($this->request->data['Event'])) {
$this->request->data['Event'] = $this->request->data;
}
if (!empty($this->request->data['Event']['filecontent'])) {
$data = $this->request->data['Event']['filecontent'];
$isXml = $data[0] === '<';
@ -2557,7 +2560,7 @@ class EventsController extends AppController
}
}
public function populate($id)
public function populate($id, $regenerateUUIDs=false)
{
if ($this->request->is('get') && $this->_isRest()) {
return $this->RestResponse->describe('Events', 'populate', false, $this->response->type());
@ -2579,15 +2582,25 @@ class EventsController extends AppController
}
if ($this->request->is('post') || $this->request->is('put')) {
if (isset($this->request->data['Event'])) {
$regenerateUUIDs = $this->request->data['Event']['regenerate_uuids'] ?? false;
$this->request->data = $this->request->data['Event'];
}
if (isset($this->request->data['json'])) {
$this->request->data = $this->_jsonDecode($this->request->data['json']);
}
if (isset($this->request->data['Event'])) {
$this->request->data = $this->request->data['Event'];
}
$eventToSave = $event;
$capturedObjects = ['Attribute', 'Object', 'Tag', 'Galaxy', 'EventReport'];
foreach ($capturedObjects as $objectType) {
if (!empty($this->request->data[$objectType])) {
if (!empty($regenerateUUIDs)) {
foreach ($this->request->data[$objectType] as $i => $obj) {
unset($this->request->data[$objectType][$i]['id']);
unset($this->request->data[$objectType][$i]['uuid']);
}
}
$eventToSave['Event'][$objectType] = $this->request->data[$objectType];
}
}
@ -4308,7 +4321,7 @@ class EventsController extends AppController
),
'bro' => array(
'url' => $this->baseurl . '/attributes/bro/download/all/false/' . $id,
// 'url' => '/attributes/restSearch/returnFormat:bro/published:1||0/eventid:' . $id,
// 'url' => $this->baseurl . '/attributes/restSearch/returnFormat:bro/published:1||0/eventid:' . $id,
'text' => __('Bro rules'),
'requiresPublished' => false,
'checkbox' => false,

View File

@ -1218,8 +1218,18 @@ class ObjectsController extends AppController
));
foreach ($object_references as $i => $object_reference) {
$temp_object = $this->MispObject->find('first', array('id' => $object_reference['ObjectReference']['object_id'], 'recursive' => -1));
$temp_attribute = $this->MispObject->Attribute->find('first', array('id' => $object_reference['ObjectReference']['referenced_id'], 'recursive' => -1));
$temp_object = $this->MispObject->find('first', [
'conditions' => [
'id' => $object_reference['ObjectReference']['object_id']
],
'recursive' => -1
]);
$temp_attribute = $this->MispObject->Attribute->find('first', [
'conditions' => [
'id' => $object_reference['ObjectReference']['referenced_id'],
],
'recursive' => -1
]);
if (!empty($temp_object) && !empty($temp_attribute)) {
$temp_object = $temp_object['Object'];
$temp_attribute = $temp_attribute['Attribute'];

View File

@ -1691,8 +1691,9 @@ class ServersController extends AppController
if (!function_exists('getallheaders')) {
$headers = [];
foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) === 'HTTP_') {
$headers[strtolower(str_replace('_', '-', substr($name, 5)))] = $value;
$name = strtolower($name);
if (substr($name, 0, 5) === 'http_') {
$headers[str_replace('_', '-', substr($name, 5))] = $value;
}
}
} else {
@ -1725,6 +1726,7 @@ class ServersController extends AppController
if (!$server) {
throw new NotFoundException(__('Invalid server'));
}
@session_write_close(); // close session to allow concurrent requests
$result = $this->Server->runConnectionTest($server);
if ($result['status'] == 1) {
if (isset($result['info']['version']) && preg_match('/^[0-9]+\.+[0-9]+\.[0-9]+$/', $result['info']['version'])) {

View File

@ -62,8 +62,10 @@ class ShadowAttributesController extends AppController
// If the old_id is set to anything but 0 then we're dealing with a proposed edit to an existing attribute
if ($shadow['old_id'] != 0) {
// Find the live attribute by the shadow attribute's uuid, so we can begin editing it
$this->Attribute->contain = 'Event';
$activeAttribute = $this->Attribute->findByUuid($shadow['uuid']);
$activeAttribute = $this->Attribute->find('first', [
'conditions' => ['Attribute.uuid' => $shadow['uuid']],
'contain' => ['Event'],
]);
// Send those away that shouldn't be able to edit this
if (!$this->__canModifyEvent($activeAttribute)) {

View File

@ -1230,6 +1230,11 @@ class UsersController extends AppController
$this->Bruteforce->insert($this->request->data['User']['email']);
}
}
//
// Actions needed for the first access, when the database is not populated yet.
//
// populate the DB with the first role (site admin) if it's empty
if (!$this->User->Role->hasAny()) {
$siteAdmin = array('Role' => array(
@ -1279,7 +1284,6 @@ class UsersController extends AppController
}
$org_id = $this->User->Organisation->id;
}
// populate the DB with the first user if it's empty
if (!$this->User->hasAny()) {
if (!isset($org_id)) {
@ -1291,7 +1295,6 @@ class UsersController extends AppController
$org_id = $firstOrg['Organisation']['id'];
}
}
$this->User->runUpdates();
$this->User->createInitialUser($org_id);
}
@ -1300,25 +1303,25 @@ class UsersController extends AppController
private function _postlogin()
{
$this->User->extralog($this->Auth->user(), "login");
$this->User->Behaviors->disable('SysLogLogable.SysLogLogable');
$this->User->id = $this->Auth->user('id');
$user = $this->User->find('first', array(
'conditions' => array(
'User.id' => $this->Auth->user('id')
),
'recursive' => -1
));
unset($user['User']['password']);
$this->User->updateLoginTimes($user['User']);
$lastUserLogin = $user['User']['last_login'];
$this->User->Behaviors->enable('SysLogLogable.SysLogLogable');
if ($lastUserLogin) {
$readableDatetime = (new DateTime())->setTimestamp($lastUserLogin)->format('D, d M y H:i:s O'); // RFC822
$this->Flash->info(__('Welcome! Last login was on %s', $readableDatetime));
}
// no state changes are ever done via GET requests, so it is safe to return to the original page:
$this->redirect($this->Auth->redirectUrl());
$this->User->extralog($this->Auth->user(), "login");
$this->User->Behaviors->disable('SysLogLogable.SysLogLogable');
$this->User->id = $this->Auth->user('id');
$user = $this->User->find('first', array(
'conditions' => array(
'User.id' => $this->Auth->user('id')
),
'recursive' => -1
));
unset($user['User']['password']);
$this->User->updateLoginTimes($user['User']);
$lastUserLogin = $user['User']['last_login'];
$this->User->Behaviors->enable('SysLogLogable.SysLogLogable');
if ($lastUserLogin) {
$readableDatetime = (new DateTime())->setTimestamp($lastUserLogin)->format('D, d M y H:i:s O'); // RFC822
$this->Flash->info(__('Welcome! Last login was on %s', $readableDatetime));
}
// no state changes are ever done via GET requests, so it is safe to return to the original page:
$this->redirect($this->Auth->redirectUrl());
}
public function routeafterlogin()

View File

@ -10,14 +10,17 @@ class TrendingTagsWidget
'time_window' => 'The time window, going back in seconds, that should be included.',
'exclude' => 'List of substrings to exclude tags by - for example "sofacy" would exclude any tag containing sofacy.',
'include' => 'List of substrings to include tags by - for example "sofacy" would include any tag containing sofacy.',
'threshold' => 'Limits the number of displayed tags. Default: 10'
'threshold' => 'Limits the number of displayed tags. Default: 10',
'filter_event_tags' => 'Filters to be applied on event tags',
'over_time' => 'Toggle the trending to be over time',
);
public $placeholder =
'{
'{
"time_window": "86400",
"threshold": 15,
"exclude": ["tlp:", "pap:"],
"include": ["misp-galaxy:", "my-internal-taxonomy"]
"include": ["misp-galaxy:", "my-internal-taxonomy"],
"filter_event_tags": ["misp-galaxy:threat-actor="APT 29"],
}';
public $description = 'Widget showing the trending tags over the past x seconds, along with the possibility to include/exclude tags.';
public $cacheLifetime = 600;
@ -30,33 +33,85 @@ class TrendingTagsWidget
$params = [
'timestamp' => time() - (empty($options['time_window']) ? 8640000 : $options['time_window']),
];
if (!empty($options['filter_event_tags'])) {
$params['event_tags'] = $options['filter_event_tags'];
}
$eventIds = $eventModel->filterEventIds($user, $params);
$tags = [];
$tagColours = [];
if (!empty($eventIds)) {
$eventTags = $eventModel->EventTag->find('all', [
'conditions' => ['EventTag.event_id' => $eventIds],
'contain' => ['Tag' => ['fields' => ['name', 'colour']]],
'recursive' => -1,
'fields' => ['id'],
]);
$allTags = [];
$this->render = $this->getRenderer($options);
if (!empty($options['over_time'])) {
foreach ($eventTags as $eventTag) {
$tagName = $eventTag['Tag']['name'];
if (isset($tags[$tagName])) {
$tags[$tagName]++;
} else if ($this->checkTag($options, $tagName)) {
$tags[$tagName] = 1;
$tagColours[$tagName] = $eventTag['Tag']['colour'];
$tagOvertime = [];
if (!empty($eventIds)) {
$events = $eventModel->fetchEvent($user, [
'eventid' => $eventIds,
'order' => 'Event.timestamp',
]);
foreach ($events as $event) {
$timestamp = $event['Event']['timestamp'];
$timestamp = strftime('%Y-%m-%d', $timestamp);
foreach ($event['EventTag'] as $tag) {
$tagName = $tag['Tag']['name'];
if (isset($tagOvertime[$timestamp][$tagName])) {
$tagOvertime[$timestamp][$tagName]++;
} else if ($this->checkTag($options, $tagName)) {
$tagOvertime[$timestamp][$tagName] = 1;
$tagColours[$tagName] = $tag['Tag']['colour'];
$allTags[$tagName] = $tagName;
}
}
}
}
arsort($tags);
$data = [];
$data['data'] = [];
foreach($tagOvertime as $date => $tagCount) {
$item = [];
$item['date'] = $date;
foreach ($allTags as $tagName) {
if (!empty($tagCount[$tagName])) {
$item[$tagName] = $tagCount[$tagName];
} else {
$item[$tagName] = 0;
}
}
$data['data'][] = $item;
}
uasort($data['data'], function ($a, $b) {
return ($a['date'] < $b['date']) ? -1 : 1;
});
$data['data'] = array_values($data['data']);
return $data;
} else {
$tags = [];
if (!empty($eventIds)) {
$eventTags = $eventModel->EventTag->find('all', [
'conditions' => ['EventTag.event_id' => $eventIds],
'contain' => ['Tag' => ['fields' => ['name', 'colour']]],
'recursive' => -1,
'fields' => ['id'],
]);
foreach ($eventTags as $eventTag) {
$tagName = $eventTag['Tag']['name'];
if (isset($tags[$tagName])) {
$tags[$tagName]++;
} else if ($this->checkTag($options, $tagName)) {
$tags[$tagName] = 1;
$tagColours[$tagName] = $eventTag['Tag']['colour'];
}
}
arsort($tags);
$data['data'] = array_slice($tags, 0, $threshold);
$data['colours'] = $tagColours;
}
}
$data['data'] = array_slice($tags, 0, $threshold);
$data['colours'] = $tagColours;
return $data;
}
@ -80,4 +135,9 @@ class TrendingTagsWidget
return true;
}
}
public function getRenderer(array $options)
{
return !empty($options['over_time']) ? 'MultiLineChart' : 'BarChart';
}
}

View File

@ -84,7 +84,7 @@ class AppModel extends Model
87 => false, 88 => false, 89 => false, 90 => false, 91 => false, 92 => false,
93 => false, 94 => false, 95 => true, 96 => false, 97 => true, 98 => false,
99 => false, 100 => false, 101 => false, 102 => false, 103 => false, 104 => false,
105 => false
105 => false, 106 => false
);
const ADVANCED_UPDATES_DESCRIPTION = array(
@ -1910,7 +1910,7 @@ class AppModel extends Model
`uuid` varchar(40) COLLATE utf8_bin NOT NULL ,
`name` varchar(191) NOT NULL,
`owner` varchar(191) NOT NULL,
`baseurl` int(11) NOT NULL DEFAULT 0,
`baseurl` varchar(191) NOT NULL,
`api_root` varchar(191) NOT NULL DEFAULT 0,
`description` text,
`filters` text,
@ -1941,6 +1941,9 @@ class AppModel extends Model
}
}
break;
case 106:
$sqlArray[] = "ALTER TABLE `taxii_servers` MODIFY `baseurl` varchar(191) NOT NULL;";
break;
case 'fixNonEmptySharingGroupID':
$sqlArray[] = 'UPDATE `events` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
$sqlArray[] = 'UPDATE `attributes` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';

View File

@ -3023,6 +3023,100 @@ class Attribute extends AppModel
return $totalCount + $incrementTotalBy;
}
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);
}
public function set_filter_uuid(&$params, $conditions, $options)
{
if (!empty($params['uuid'])) {

View File

@ -2097,7 +2097,7 @@ class Event extends AppModel
// Include information about event creator user email. This information is included for:
// - users from event creator org
// - site admins
// In export, this information will be included in `event_creator_email` field just for auditors of event creator org.
// In export, this information will be included in `event_creator_email` field for auditors of event creator org and site admins.
$sameOrg = $event['Event']['orgc_id'] === $user['org_id'];
if ($sameOrg || $user['Role']['perm_site_admin']) {
if (!isset($userEmails[$event['Event']['user_id']])) {
@ -2105,7 +2105,7 @@ class Event extends AppModel
}
$userEmail = $userEmails[$event['Event']['user_id']];
if ($sameOrg && $user['Role']['perm_audit']) {
if ($sameOrg && $user['Role']['perm_audit'] || $user['Role']['perm_site_admin']) {
$event['Event']['event_creator_email'] = $userEmail;
}
$event['User']['email'] = $userEmail;
@ -3373,7 +3373,11 @@ class Event extends AppModel
foreach ($event['EventTag'] as $tag) {
$tagId = $this->captureTagWithCache($tag['Tag'], $user, $capturedTags);
if ($tagId && !in_array($tagId, $event_tag_ids)) {
$eventTags[] = array('tag_id' => $tagId);
$eventTags[] = array(
'tag_id' => $tagId,
'local' => isset($tag['local']) ? $tag['local'] : 0,
'relationship_type' => isset($tag['relationship_type']) ? $tag['relationship_type'] : '',
);
$event_tag_ids[] = $tagId;
}
}
@ -3388,6 +3392,7 @@ class Event extends AppModel
$eventTags[] = [
'tag_id' => $tag_id,
'local' => isset($tag['local']) ? $tag['local'] : 0,
'relationship_type' => isset($tag['relationship_type']) ? $tag['relationship_type'] : '',
];
$event_tag_ids[] = $tag_id;
}
@ -3448,7 +3453,11 @@ class Event extends AppModel
$a['AttributeTag'] = array($a['AttributeTag']);
}
foreach ($a['AttributeTag'] as $tag) {
$attributeTags[] = array('tag_id' => $this->captureTagWithCache($tag['Tag'], $user, $capturedTags));
$attributeTags[] = array(
'tag_id' => $this->captureTagWithCache($tag['Tag'], $user, $capturedTags),
'local' => isset($tag['local']) ? $tag['local'] : 0,
'relationship_type' => isset($tag['relationship_type']) ? $tag['relationship_type'] : '',
);
}
}
if (isset($a['Tag'])) {
@ -3461,6 +3470,7 @@ class Event extends AppModel
$attributeTags[] = [
'tag_id' => $tagId,
'local' => isset($tag['local']) ? $tag['local'] : 0,
'relationship_type' => isset($tag['relationship_type']) ? $tag['relationship_type'] : '',
];
}
}

View File

@ -36,7 +36,6 @@ class WorkflowBaseModule
{
$fullIndexedParams = [];
foreach ($this->params as $param) {
$param['value'] = $nodeParamByID[$param['id']]['value'] ?? null;
$param['value'] = $node['data']['indexed_params'][$param['id']] ?? null;
$fullIndexedParams[$param['id']] = $param;
}

View File

@ -5,6 +5,7 @@ class Module_ms_teams_webhook extends Module_webhook
{
public $id = 'ms-teams-webhook';
public $name = 'MS Teams Webhook';
public $version = '0.2';
public $description = 'Perform callbacks to the MS Teams webhook provided by the "Incoming Webhook" connector';
public $icon_path = 'MS_Teams.png';
@ -37,7 +38,7 @@ class Module_ms_teams_webhook extends Module_webhook
];
}
protected function doRequest($url, $contentType, $data)
protected function doRequest($url, $contentType, $data, $headers = [], $serverConfig = null)
{
$data = '{"text":"' . implode($data) . '"}';
return parent::doRequest($url, $contentType, $data);

View File

@ -4,20 +4,17 @@ include_once APP . 'Model/WorkflowModules/WorkflowBaseModule.php';
App::uses('SyncTool', 'Tools');
App::uses('JsonTool', 'Tools');
class Module_splunk_hec_export extends WorkflowBaseActionModule
class Module_splunk_hec_export extends Module_webhook
{
public $id = 'splunk-hec-export';
public $name = 'Splunk HEC export';
public $version = '0.1';
public $description = 'Export Event Data to Splunk HTTP Event Collector';
public $version = '0.2';
public $description = 'Export Event Data to Splunk HTTP Event Collector. Due to the potential high amount of requests, it\'s recommanded to put this module after a `concurrent_task` logic module.';
public $icon_path = 'Splunk.png';
public $inputs = 1;
public $outputs = 0;
public $support_filters = false;
public $expect_misp_core_format = true;
public $params = [];
private $timeout = false;
private $Event;
public $outputs = 0;
public function __construct()
{
@ -34,10 +31,10 @@ class Module_splunk_hec_export extends WorkflowBaseActionModule
'label' => __('Verify HTTPS Certificate'),
'type' => 'select',
'options' => [
'true' => __('True'),
'false' => __('False'),
'1' => __('True'),
'0' => __('False'),
],
'default' => 'true',
'default' => 1,
],
[
'id' => 'hec_token',
@ -46,15 +43,23 @@ class Module_splunk_hec_export extends WorkflowBaseActionModule
'type' => 'input',
'placeholder' => '00000000-0000-0000-000000000000'
],
[
'id' => 'source_type',
'label' => __('Source Type'),
'type' => 'select',
'type' => 'input',
'default' => '',
'placeholder' => 'misp:event'
],
[
'id' => 'event_per_attribute',
'label' => __('Create one Splunk Event per Attribute'),
'type' => 'select',
'options' => [
'true' => __('True'),
'false' => __('False'),
'1' => __('True'),
'0' => __('False'),
],
'default' => 'false',
'default' => 0,
],
[
'id' => 'data_extraction_model',
@ -66,28 +71,8 @@ class Module_splunk_hec_export extends WorkflowBaseActionModule
];
}
public function diagnostic(): array
{
$errors = array_merge(parent::diagnostic(), []);
if (empty(Configure::read('Security.rest_client_enable_arbitrary_urls'))) {
$errors = $this->addNotification(
$errors,
'error',
__('`rest_client_enable_arbitrary_urls` is turned off.'),
__('The module will not send any request as long as `Security.rest_client_enable_arbitrary_urls` is turned off.'),
[
__('This is a security measure to ensure a site-admin do not send arbitrary request to internal services')
],
true,
true
);
}
return $errors;
}
public function exec(array $node, WorkflowRoamingData $roamingData, array &$errors = []): bool
{
parent::exec($node, $roamingData, $errors);
if (empty(Configure::read('Security.rest_client_enable_arbitrary_urls'))) {
$errors[] = __('`Security.rest_client_enable_arbitrary_urls` is turned off');
return false;
@ -97,45 +82,70 @@ class Module_splunk_hec_export extends WorkflowBaseActionModule
$errors[] = __('URL not provided.');
return false;
}
if (empty($params['hec_token']['value'])) {
$errors[] = __('Authorization token not provided.');
return false;
}
$rData = $roamingData->getData();
//$path = $params['data_extraction_path']['value'];
//$extracted = !empty($params['data_extraction_path']['value']) ? $this->extractData($rData, $path) : $rData;
$event_without_attributes = $rData['Event'];
unset($event_without_attributes['Attribute']);
unset($event_without_attributes['_AttributeFlattened']);
$splunk_events = [];
if ($params['event_per_attribute']['value'] == 'true') {
if (!empty($params['event_per_attribute']['value'])) {
foreach ($rData['Event']['Attribute'] as $attribute) {
array_push($splunk_events, [
'Attribute' => $attribute,
'Event' => $event_without_attributes
]);
$splunk_events[] = [
'Attribute' => $attribute,
'Event' => $event_without_attributes
];
}
} else {
array_push($splunk_events, $rData);
$splunk_events[] = $rData;
}
if (!empty($params['data_extraction_model']['value'])) {
$data_extraction_model = JsonTool::decode($params['data_extraction_model']['value']);
$extracted_events = [];
foreach ($splunk_events as $splunk_event) {
$event = array();
foreach ($data_extraction_model as $field => $path) {
$field_data = $this->extractData($splunk_event, $path);
$event[$field] = count($field_data) == 1 ? $field_data[0] : $field_data; // unpack if only one element
}
array_push($extracted_events, $event);
}
$splunk_events = $extracted_events;
}
if (!empty($params['data_extraction_model']['value'])) {
$data_extraction_model = JsonTool::decode($params['data_extraction_model']['value']);
$extracted_events = [];
foreach ($splunk_events as $splunk_event) {
$event = [];
foreach ($data_extraction_model as $field => $path) {
$field_data = $this->extractData($splunk_event, $path);
$event[$field] = count($field_data) == 1 ? $field_data[0] : $field_data; // unpack if only one element
}
$extracted_events[] = $event;
}
$splunk_events = $extracted_events;
}
return $this->sendToSplunk($splunk_events, $params['hec_token']['value'], $params['url']['value'], $params['source_type']['value']);
}
protected function sendToSplunk(array $splunk_events, $token, $url, $source_type): bool
{
foreach ($splunk_events as $splunk_event) {
try {
$response = $this->doRequest($params['url']['value'], $params['hec_token']['value'], $params['verify_tls']['value'], $splunk_event);
$headers = [
'Authorization' => "Splunk {$token}",
];
$serverConfig = [
'Server' => ['self_signed' => empty($params['verify_tls']['value'])]
];
$hec_event = [
'event' => $splunk_event
];
if (!empty($source_type)) {
$hec_event['sourcetype'] = $source_type;
}
$response = $this->doRequest(
$url,
'json',
$hec_event,
$headers,
$serverConfig,
);
if (!$response->isOk()) {
if ($response->code === 403 || $response->code === 401) {
$errors[] = __('Authentication failed.');
@ -154,33 +164,4 @@ class Module_splunk_hec_export extends WorkflowBaseActionModule
}
return true;
}
protected function doRequest($url, $hec_token, $verify_tls, $data)
{
$this->Event = ClassRegistry::init('Event'); // We just need a model to use AppModel functions
$version = implode('.', $this->Event->checkMISPVersion());
$commit = $this->Event->checkMIPSCommit();
$request = [
'header' => [
'Authorization' => 'Splunk ' . $hec_token,
]
];
$syncTool = new SyncTool();
$server = [];
if ($verify_tls == 'false') {
$server['Server'] = ['self_signed' => true];
}
$HttpSocket = $syncTool->setupHttpSocket($server, $this->timeout, 'Server');
$HEC_Event = [
'event' => $data,
];
$response = $HttpSocket->post($url, JsonTool::encode($HEC_Event), $request);
return $response;
}
}

View File

@ -8,7 +8,7 @@ class Module_webhook extends WorkflowBaseActionModule
{
public $id = 'webhook';
public $name = 'Webhook';
public $version = '0.2';
public $version = '0.3';
public $description = 'Allow to perform custom callbacks to the provided URL';
public $icon_path = 'webhook.png';
public $inputs = 1;
@ -106,21 +106,22 @@ class Module_webhook extends WorkflowBaseActionModule
return false;
}
protected function doRequest($url, $contentType, $data)
protected function doRequest($url, $contentType, $data, $headers = [], $serverConfig = null)
{
$this->Event = ClassRegistry::init('Event'); // We just need a model to use AppModel functions
$version = implode('.', $this->Event->checkMISPVersion());
$commit = $this->Event->checkMIPSCommit();
$request = [
'header' => [
'header' => array_merge([
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'User-Agent' => 'MISP ' . $version . (empty($commit) ? '' : ' - #' . $commit),
]
], $headers)
];
$syncTool = new SyncTool();
$HttpSocket = $syncTool->setupHttpSocket(null, $this->timeout);
$serverConfig = !empty($serverConfig['Server']) ? $serverConfig : ['Server' => $serverConfig];
$HttpSocket = $syncTool->setupHttpSocket($serverConfig, $this->timeout);
if ($contentType == 'form') {
$request['header']['Content-Type'] = 'application/x-www-form-urlencoded';
$response = $HttpSocket->post($url, $data, $request);

View File

@ -1,48 +1,59 @@
<div class="logs index">
<h2><?= __('Audit logs for event #%s', intval($event['Event']['id'])) ?></h2>
<div class="pagination">
<ul>
<?php
$paginator = $this->LightPaginator->prev('&laquo; ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
$paginator .= $this->LightPaginator->next(__('next') . ' &raquo;', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
echo $paginator;
?>
<li><a href="<?= $baseurl . '/logs/event_index/' . intval($event['Event']['id']) ?>"><?= __('Older logs') ?></a></li>
</ul>
</div>
<table class="table table-striped table-hover table-condensed">
<tr>
<th><?= $this->LightPaginator->sort('created') ?></th>
<th><?= $this->LightPaginator->sort('user_id', __('User')) ?></th>
<th><?= $this->LightPaginator->sort('org_id', __('Org')) ?></th>
<th><?= $this->LightPaginator->sort('action') ?></th>
<th><?= __('Model') ?></th>
<th><?= __('Title') ?></th>
<th><?= __('Change') ?></th>
</tr>
<?php foreach ($list as $item): ?>
<tr>
<td class="short"><?= $this->Time->time($item['AuditLog']['created']); ?></td>
<td class="short"><?php
if (isset($item['AuditLog']['user_id']) && $item['AuditLog']['user_id'] == 0) {
echo __('SYSTEM');
} else if (isset($item['User']['email'])) {
echo h($item['User']['email']);
} ?></td>
<td class="short"><?= isset($item['Organisation']) ? $this->OrgImg->getOrgLogo($item, 24) : '' ?></td>
<td class="short"><?= h($item['AuditLog']['action_human']) ?></td>
<td class="short"><?= h($item['AuditLog']['model']) . ' #' . intval($item['AuditLog']['model_id']) ?></td>
<td class="limitedWidth"><?= h($item['AuditLog']['title']) ?></td>
<td><?= $this->element('AuditLog/change', ['item' => $item]) ?></td>
</tr>
<?php endforeach; ?>
</table>
<div class="pagination">
<ul>
<?= $paginator ?>
<li><a href="<?= $baseurl . '/logs/event_index/' . intval($event['Event']['id']) ?>"><?= __('Older logs') ?></a></li>
</ul>
</div>
</div>
<?= $this->element('/genericElements/SideMenu/side_menu', ['menuList' => 'event', 'menuItem' => 'eventLog']);
<?php
echo sprintf('<div%s>', empty($ajax) ? ' class="index"' : '');
echo $this->element('genericElements/IndexTable/index_table', [
'data' => [
'light_paginator' => 1,
'data' => $data,
'fields' => [
[
'name' => __('Created'),
'data_path' => 'AuditLog.created',
'sort' => 'AuditLog.created',
'class' => 'short',
'element' => 'time'
],
[
'name' => __('User'),
'data_path' => 'User.email',
'sort' => 'User.email',
'class' => 'short',
'empty' => 'SYSTEM'
],
[
'name' => __('Organisation'),
'data_path' => 'Organisation',
'sort' => 'Organisation.name',
'element' => 'org',
'class' => 'short'
],
[
'name' => __('Action'),
'data_path' => 'AuditLog.action_human',
'sort' => 'AuditLog.action_human',
'class' => 'short'
],
[
'name' => __('Model'),
'data_path' => 'AuditLog',
'element' => 'model',
'class' => 'short'
],
[
'name' => __('Title'),
'data_path' => 'AuditLog.title',
'class' => 'limitedWidth'
],
[
'name' => __('Change'),
'data_path' => 'AuditLog',
'element' => 'custom_element',
'element_path' => 'AuditLog/change'
]
],
'title' => __('Audit logs for event #%s', intval($event['Event']['id']))
]
]);
echo '</div>';
if (empty($ajax)) {
echo $this->element('/genericElements/SideMenu/side_menu', $menuData);
}

View File

@ -12,7 +12,7 @@
<pre class="quickSelect"><?= h($entity['AuthKey']['authkey_raw']) ?></pre>
</div>
<div class="modal-footer">
<a href="<?= $referer ?>" class="btn btn-primary"><?= __('I have noted down my key, take me back now') ?></a>
<a href="<?= h($referer) ?>" class="btn btn-primary"><?= __('I have noted down my key, take me back now') ?></a>
</div>
</div>
<?php
@ -22,7 +22,7 @@
<p><?= __('Please make sure that you note down the auth key below, this is the only time the auth key is shown in plain text, so make sure you save it. If you lose the key, simply remove the entry and generate a new one.'); ?></p>
<p><?=__('MISP will use the first and the last 4 characters for identification purposes.')?></p>
<pre class="quickSelect"><?= h($entity['AuthKey']['authkey_raw']) ?></pre>
<a href="<?= $referer ?>" class="btn btn-primary"><?= __('I have noted down my key, take me back now') ?></a>
<a href="<?= h($referer) ?>" class="btn btn-primary"><?= __('I have noted down my key, take me back now') ?></a>
<?php
}
?>

View File

@ -159,9 +159,9 @@ $type_mapper = [
.addClass(jqXHR.status == 200 ? 'label-success' : 'label-important')
if (typeof result === 'object') {
$executionResultText.text(JSON.stringify(result, '', 4));
$('#executionResultHtml').empty();
} else {
$('#executionResultHtml').html(result);
// $executionResultText.text(result);
}
}

View File

@ -75,6 +75,9 @@
'tag_display_style' => 2
]);
}
if (empty($hTags)) {
$hTags = sprintf('<span class="grey">-%s-</span>', __('none'));
}
$highlightedTagsString .= sprintf(
'<tr><td style="font-weight: bold;text-transform: uppercase;">%s</td></td><td>%s</td><td>%s</td></tr>',

View File

@ -0,0 +1 @@
<?= $this->element($field['element_path'], ['item' => $row]) ?>

View File

@ -1,5 +1,8 @@
<?php
$data = Hash::extract($row, $field['data_path']);
if (!empty($field['empty']) && empty($data)) {
$data = $field['empty'];
}
if (is_array($data)) {
if (count($data) > 1) {
$implodeGlue = isset($field['array_implode_glue']) ? $field['array_implode_glue'] : ', ';

View File

@ -0,0 +1,3 @@
<?php
$data = Hash::extract($row, $field['data_path']);
echo h($data['model']) . ' #' . intval($data['model_id']);

View File

@ -0,0 +1,3 @@
<?php
$time = Hash::extract($row, $field['data_path'])[0];
echo $this->Time->time($time);

View File

@ -10,7 +10,13 @@
[
'field' => 'json',
'class' => 'input-big-chungus',
'type' => 'textarea'
'type' => 'textarea',
],
[
'field' => 'regenerate_uuids',
'type' => 'checkbox',
'label' => __('Regenerate UUIDs'),
'title' => __('test'),
],
],
'submit' => [

View File

@ -73,7 +73,7 @@ echo $this->element('genericElements/Form/genericForm', [
'field' => 'orgc_id',
'label' => __('Creator organisation'),
'options' => $dropdownData['orgs'],
'value' => $this->request->params['action'] === 'add' ? $me['org_id'] : '',
'value' => $this->request->params['action'] === 'add' ? $me['org_id'] : null,
'type' => 'dropdown',
'div' => ['id' => 'OrgcDiv', 'style' => 'display:none', 'class' => 'optionalField'],
'class' => 'form-control span6'

View File

@ -1,22 +1,24 @@
<div class="logs index">
<h2><?php echo __('Logs');?></h2>
<p><?= __('Showing log entries for data currently stored in the database. Entries about hard-deleted data have been omitted.') ?></p>
<div class="pagination">
<ul>
<?php
echo $this->Paginator->prev('&laquo; ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
echo $this->Paginator->next(__('next') . ' &raquo;', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
$this->LightPaginator->options(array('url' => $this->passedArgs));
echo $this->LightPaginator->prev('&laquo; ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
echo $this->LightPaginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
echo $this->LightPaginator->next(__('next') . ' &raquo;', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
?>
</ul>
</div>
<table class="table table-striped table-hover table-condensed">
<tr>
<th><?php echo $this->Paginator->sort('org');?></th>
<th><?php echo $this->Paginator->sort('email');?></th>
<th><?php echo $this->Paginator->sort('action');?></th>
<th><?php echo $this->Paginator->sort('model');?></th>
<th><?php echo $this->Paginator->sort('title');?></th>
<th><?php echo $this->Paginator->sort('created');?></th>
<th><?php echo $this->LightPaginator->sort('org');?></th>
<th><?php echo $this->LightPaginator->sort('email');?></th>
<th><?php echo $this->LightPaginator->sort('action');?></th>
<th><?php echo $this->LightPaginator->sort('model');?></th>
<th><?php echo $this->LightPaginator->sort('title');?></th>
<th><?php echo $this->LightPaginator->sort('created');?></th>
</tr>
<?php foreach ($list as $item): ?>
<tr>
@ -39,7 +41,7 @@
</table>
<p>
<?php
echo $this->Paginator->counter(array(
echo $this->LightPaginator->counter(array(
'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
));
?>
@ -47,9 +49,9 @@
<div class="pagination">
<ul>
<?php
echo $this->Paginator->prev('&laquo; ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
echo $this->Paginator->next(__('next') . ' &raquo;', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
echo $this->LightPaginator->prev('&laquo; ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
echo $this->LightPaginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
echo $this->LightPaginator->next(__('next') . ' &raquo;', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
?>
</ul>
</div>

@ -1 +1 @@
Subproject commit ac1242a40e3a165ea664f3a8640dc346a5877c3a
Subproject commit aad2e33b80e3c6221cc63529b58ee837d65e651b

@ -1 +1 @@
Subproject commit 4e19aa30ba94940e38bf50164248a572139ca520
Subproject commit fd603be3283953b68ed48ede7afd2e19f43577ac

@ -1 +1 @@
Subproject commit c60a6e76ccd735d460b382effee9af6aae7fa4ab
Subproject commit a794fdf0d55aa9bdb15f778c826935ada52c6b39

@ -1 +1 @@
Subproject commit a33dd623d1936dc015a3ba286a1b83eea1f71459
Subproject commit 14f1349fad189091960311018a4cabcb1018adb9

@ -1 +1 @@
Subproject commit ab2938e008eb5ec085d9e9c8e7c5c4d6fd466a39
Subproject commit a51a9adc6c693bd5d2bf83f49920df7247ced298

View File

@ -162,7 +162,7 @@ class ActionTable {
tr.id = "tr_" + this.__uuidv4();
for (var col of row) {
var td = document.createElement('td');
td.innerHTML = col;
td.textContent = col;
tr.appendChild(td);
}
this.__add_action_button(tr);

View File

@ -636,7 +636,7 @@ class EventGraph {
btn_plot.data('network-preview', preview);
btn_plot.popover({
container: 'body',
content: function() { return '<img style="width: 500px; height: 150px;" src="' + $(this).data('network-preview') + '" />'; },
content: function() { return '<img style="width: 500px; height: 150px;" src="' + $('<div>').text($(this).data('network-preview')).html() + '" />'; },
placement: 'right',
trigger: 'hover',
template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content" style="width: 500px; height: 150px;"></div></div>',
@ -2002,7 +2002,7 @@ function reset_graph_history() {
btn_plot.data('network-preview', preview);
btn_plot.popover({
container: 'body',
content: function() { return '<img style="width: 500px; height: 150px;" src="' + $(this).data('network-preview') + '" />'; },
content: function() { return '<img style="width: 500px; height: 150px;" src="' + $('<div>').text($(this).data('network-preview')).html() + '" />'; },
placement: 'right',
trigger: 'hover',
template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content" style="width: 500px; height: 150px;"></div></div>',

View File

@ -659,4 +659,3 @@ systemctl restart misp-workers.service
via this guide and will need additional investigation.
{!generic/hardening.md!}

View File

@ -167,10 +167,10 @@ with open('../../misp-book/categories-and-types/README.md', 'w') as f:
# Find the offset of the start header: "### MISP default attributes and categories"
# Find the offset of the end/next header: "## MISP objects"
# Replace our new content in between
print("Updating MISP website - ../../misp-website/_pages/datamodels.md")
print("Updating MISP website - ../../misp-website/content/datamodels.md")
misp_website = []
store_lines = True
with open('../../misp-website/_pages/datamodels.md', 'r') as f:
with open('../../misp-website/content/datamodels.md', 'r') as f:
for line in f:
# start marker
if store_lines:
@ -183,7 +183,7 @@ with open('../../misp-website/_pages/datamodels.md', 'r') as f:
elif line.startswith('## MISP objects'):
store_lines = True
misp_website.append(line)
with open('../../misp-website/_pages/datamodels.md', 'w') as f:
with open('../../misp-website/content/datamodels.md', 'w') as f:
f.write(''.join(misp_website))