Merge branch '2.4' of github.com:MISP/MISP into 2.4

pull/4046/head
iglocska 2019-01-20 22:17:39 +01:00
commit 631184a2ca
15 changed files with 282 additions and 214 deletions

View File

@ -1 +1 @@
{"major":2, "minor":4, "hotfix":100}
{"major":2, "minor":4, "hotfix":101}

View File

@ -407,6 +407,7 @@ class AppController extends Controller
$this->set('me', $this->Auth->user());
$this->set('isAdmin', $role['perm_admin']);
$this->set('isSiteAdmin', $role['perm_site_admin']);
$this->set('hostOrgUser', $this->Auth->user('org_id') == Configure::read('MISP.host_org_id'));
$this->set('isAclAdd', $role['perm_add']);
$this->set('isAclModify', $role['perm_modify']);
$this->set('isAclModifyOrg', $role['perm_modify_org']);

View File

@ -159,7 +159,7 @@ class ACLComponent extends Component
'feeds' => array(
'add' => array(),
'cacheFeeds' => array(),
'compareFeeds' => array(),
'compareFeeds' => array('*'),
'delete' => array(),
'disable' => array(),
'edit' => array(),
@ -169,11 +169,11 @@ class ACLComponent extends Component
'fetchSelectedFromFreetextIndex' => array(),
'getEvent' => array(),
'importFeeds' => array(),
'index' => array(),
'previewEvent' => array(),
'previewIndex' => array(),
'index' => array('*'),
'previewEvent' => array('*'),
'previewIndex' => array('*'),
'toggleSelected' => array('perm_site_admin'),
'view' => array(),
'view' => array('*'),
),
'galaxies' => array(
'attachCluster' => array('perm_tagger'),
@ -255,6 +255,7 @@ class ACLComponent extends Component
'delete' => array('perm_object_template'),
'getToggleField' => array(),
'objectChoice' => array('*'),
'objectMetaChoice' => array('perm_add'),
'view' => array('*'),
'viewElements' => array('*'),
'index' => array('*'),
@ -311,6 +312,7 @@ class ACLComponent extends Component
),
'servers' => array(
'add' => array(),
'cache' => array('perm_site_admin'),
'checkout' => array(),
'delete' => array(),
'deleteFile' => array(),

View File

@ -23,13 +23,16 @@ class FeedsController extends AppController
{
parent::beforeFilter();
$this->Security->unlockedActions = array('previewIndex');
if (!$this->_isSiteAdmin()) {
if (!$this->_isSiteAdmin() && $this->Auth->user('org_id') != Configure::read('MISP.host_org_id')) {
throw new MethodNotAllowedException(__('You don\'t have the required privileges to do that.'));
}
}
public function index()
{
if (!$this->_isSiteAdmin() && !$this->Auth->user('org_id') == Configure::read('MISP.host_org_id')) {
throw NotAllowedException('You don\'t have access to this feature.');
}
$this->Feed->load_default_feeds();
$scope = isset($this->passedArgs['scope']) ? $this->passedArgs['scope'] : 'all';
if ($scope !== 'all') {
@ -77,6 +80,9 @@ class FeedsController extends AppController
public function view($feedId)
{
if (!$this->_isSiteAdmin() && !$this->Auth->user('org_id') == Configure::read('MISP.host_org_id')) {
throw NotAllowedException('You don\'t have access to this feature.');
}
$feed = $this->Feed->find('first', array(
'conditions' => array('Feed.id' => $feedId),
'recursive' => -1,
@ -500,6 +506,9 @@ class FeedsController extends AppController
public function previewIndex($feedId)
{
if (!$this->_isSiteAdmin() && !$this->Auth->user('org_id') == Configure::read('MISP.host_org_id')) {
throw NotAllowedException('You don\'t have access to this feature.');
}
$this->Feed->id = $feedId;
if (!$this->Feed->exists()) {
throw new NotFoundException(__('Invalid feed.'));
@ -680,6 +689,9 @@ class FeedsController extends AppController
public function previewEvent($feedId, $eventUuid, $all = false)
{
if (!$this->_isSiteAdmin() && !$this->Auth->user('org_id') == Configure::read('MISP.host_org_id')) {
throw NotAllowedException('You don\'t have access to this feature.');
}
$this->Feed->id = $feedId;
if (!$this->Feed->exists()) {
throw new NotFoundException(__('Invalid feed.'));
@ -839,6 +851,9 @@ class FeedsController extends AppController
public function compareFeeds($id = false)
{
if (!$this->_isSiteAdmin() && !$this->Auth->user('org_id') == Configure::read('MISP.host_org_id')) {
throw NotAllowedException('You don\'t have access to this feature.');
}
$feeds = $this->Feed->compareFeeds($id);
if ($this->_isRest()) {
return $this->RestResponse->viewData($feeds, $this->response->type());

View File

@ -54,14 +54,24 @@ class ServersController extends AppController
$params = array(
'recursive' => -1,
'contain' => array(
'Organisation' => array('Organisation.id', 'Organisation.name', 'Organisation.uuid', 'Organisation.nationality', 'Organisation.sector', 'Organisation.type'),
'RemoteOrg' => array('RemoteOrg.id', 'RemoteOrg.name', 'RemoteOrg.uuid', 'RemoteOrg.nationality', 'RemoteOrg.sector', 'RemoteOrg.type'),
)
'User' => array(
'fields' => array('User.id', 'User.org_id', 'User.email'),
),
'Organisation' => array(
'fields' => array('Organisation.id', 'Organisation.name', 'Organisation.uuid', 'Organisation.nationality', 'Organisation.sector', 'Organisation.type'),
),
'RemoteOrg' => array(
'fields' => array('RemoteOrg.id', 'RemoteOrg.name', 'RemoteOrg.uuid', 'RemoteOrg.nationality', 'RemoteOrg.sector', 'RemoteOrg.type'),
),
),
);
$servers = $this->Server->find('all', $params);
$servers = $this->Server->attachServerCacheTimestamps($servers);
return $this->RestResponse->viewData($servers, $this->response->type());
} else {
$this->set('servers', $this->paginate());
$servers = $this->paginate();
$servers = $this->Server->attachServerCacheTimestamps($servers);
$this->set('servers', $servers);
$collection = array();
$collection['orgs'] = $this->Server->Organisation->find('list', array(
'fields' => array('id', 'name'),

View File

@ -1254,6 +1254,25 @@ class Feed extends AppModel
$feeds[$k]['Feed']['values'] = $redis->sCard('misp:feed_cache:' . $feed['Feed']['id']);
}
$feeds = array_values($feeds);
$this->Server = ClassRegistry::init('Server');
$servers = $this->Server->find('all', array(
'recursive' => -1,
'fields' => array('id', 'url', 'name'),
'contain' => array('RemoteOrg' => array('fields' => array('RemoteOrg.id', 'RemoteOrg.name'))),
'conditions' => array('Server.caching_enabled')
));
foreach ($servers as $k => $server) {
if (!$redis->exists('misp:server_cache:' . $server['Server']['id'])) {
unset($servers[$k]);
continue;
}
$servers[$k]['Server']['input_source'] = 'network';
$servers[$k]['Server']['source_format'] = 'misp';
$servers[$k]['Server']['provider'] = $servers[$k]['RemoteOrg']['name'];
$servers[$k]['Server']['default'] = false;
$servers[$k]['Server']['is_misp_server'] = true;
$servers[$k]['Server']['values'] = $redis->sCard('misp:server_cache:' . $server['Server']['id']);
}
foreach ($feeds as $k => $feed) {
foreach ($feeds as $k2 => $feed2) {
if ($k == $k2) {
@ -1265,6 +1284,37 @@ class Feed extends AppModel
'overlap_percentage' => round(100 * count($intersect) / $feeds[$k]['Feed']['values']),
));
}
foreach ($servers as $k2 => $server) {
$intersect = $redis->sInter('misp:feed_cache:' . $feed['Feed']['id'], 'misp:server_cache:' . $server['Server']['id']);
$feeds[$k]['Feed']['ComparedFeed'][] = array_merge(array_intersect_key($server['Server'], $fields), array(
'overlap_count' => count($intersect),
'overlap_percentage' => round(100 * count($intersect) / $feeds[$k]['Feed']['values']),
));
}
}
foreach ($servers as $k => $server) {
foreach ($feeds as $k2 => $feed2) {
$intersect = $redis->sInter('misp:server_cache:' . $server['Server']['id'], 'misp:feed_cache:' . $feed2['Feed']['id']);
$servers[$k]['Server']['ComparedFeed'][] = array_merge(array_intersect_key($feed2['Feed'], $fields), array(
'overlap_count' => count($intersect),
'overlap_percentage' => round(100 * count($intersect) / $servers[$k]['Server']['values']),
));
}
foreach ($servers as $k2 => $server2) {
if ($k == $k2) {
continue;
}
$intersect = $redis->sInter('misp:server_cache:' . $server['Server']['id'], 'misp:server_cache:' . $server2['Server']['id']);
$servers[$k]['Server']['ComparedFeed'][] = array_merge(array_intersect_key($server2['Server'], $fields), array(
'overlap_count' => count($intersect),
'overlap_percentage' => round(100 * count($intersect) / $servers[$k]['Server']['values']),
));
}
}
foreach ($servers as $k => $server) {
$server['Feed'] = $server['Server'];
unset($server['Server']);
$feeds[] = $server;
}
return $feeds;
}

View File

@ -4296,18 +4296,19 @@ class Server extends AppModel
while ($continue) {
$i++;
$pipe = $redis->multi(Redis::PIPELINE);
$chunk_size = 100000;
$chunk_size = 50000;
$data = $this->__getCachedAttributes($server, $HttpSocket, $chunk_size, $i);
$data = explode(PHP_EOL, trim($data));
if (empty($data) || count($data) < $chunk_size) {
if (empty(trim($data))) {
$continue = false;
}
if (!empty($data)) {
} else {
$data = explode(PHP_EOL, trim($data));
foreach ($data as $entry) {
list($value, $uuid) = explode(',', $entry);
$redis->sAdd('misp:server_cache:' . $server['Server']['id'], $value);
$redis->sAdd('misp:server_cache:combined', $value);
$redis->sAdd('misp:server_cache:event_uuid_lookup:' . $value, $server['Server']['id'] . '/' . $uuid);
if (!empty($value)) {
$redis->sAdd('misp:server_cache:' . $server['Server']['id'], $value);
$redis->sAdd('misp:server_cache:combined', $value);
$redis->sAdd('misp:server_cache:event_uuid_lookup:' . $value, $server['Server']['id'] . '/' . $uuid);
}
}
}
if ($jobId) {
@ -4315,6 +4316,7 @@ class Server extends AppModel
}
$pipe->exec();
}
$redis->set('misp:server_cache_timestamp:' . $server['Server']['id'], time());
return true;
}
@ -4326,6 +4328,7 @@ class Server extends AppModel
'page' => $i,
'limit' => $chunk_size
);
debug($filter_rules);
$request = $this->setupSyncRequest($server);
try {
$response = $HttpSocket->post($server['Server']['url'] . '/attributes/restSearch.json', json_encode($filter_rules), $request);
@ -4335,115 +4338,15 @@ class Server extends AppModel
return $response->body;
}
public function attachFeedCorrelations($objects, $user, &$event, $overrideLimit = false)
public function attachServerCacheTimestamps($data)
{
$redis = $this->setupRedis();
if ($redis !== false) {
$params = array(
'recursive' => -1,
'fields' => array('id', 'name', 'url', 'provider', 'source_format')
);
if (!$user['Role']['perm_site_admin']) {
$params['conditions'] = array('Server.caching_enabled' => 1);
}
$servers = $this->find('all', $params);
$counter = 0;
$hashTable = array();
$serverList = array();
$pipe = $redis->multi(Redis::PIPELINE);
$objectsWithServerHits = array();
$hashTable = array();
$hitIds = array();
$this->Event = ClassRegistry::init('Event');
$objectKeys = array();
foreach ($objects as $k => $object) {
if (in_array($object['type'], $this->Event->Attribute->getCompositeTypes())) {
$value = explode('|', $object['value']);
$hashTable[$k] = md5($value[0]);
$objectKeys[] = $k;
} else {
$hashTable[$k] = md5($object['value']);
}
$redis->sismember('misp:server_cache:combined', $hashTable[$k]);
$objectKeys[] = $k;
}
$results = array();
$results = $pipe->exec();
if (!$overrideLimit && count($objects) > 10000) {
foreach ($results as $k => $result) {
if ($result) {
if (isset($event['ServerCount'])) {
$event['ServerCount']++;
} else {
$event['ServerCount'] = 1;
}
$objects[$k]['ServerHit'] = true;
}
}
} else {
foreach ($results as $k => $result) {
if ($result) {
$hitIds[] = $k;
}
}
foreach ($feeds as $k3 => $feed) {
$pipe = $redis->multi(Redis::PIPELINE);
foreach ($hitIds as $k2 => $k) {
$redis->sismember('misp:feed_cache:' . $feed['Feed']['id'], $hashTable[$k]);
}
$feedHits = $pipe->exec();
foreach ($feedHits as $k4 => $hit) {
if ($hit) {
if (!isset($event['Feed'][$feeds[$k3]['Feed']['id']]['id'])) {
if (!isset($event['Feed'][$feeds[$k3]['Feed']['id']])) {
$event['Feed'][$feeds[$k3]['Feed']['id']] = array();
}
$event['Feed'][$feeds[$k3]['Feed']['id']] = array_merge($event['Feed'][$feeds[$k3]['Feed']['id']], $feed['Feed']);
}
$objects[$hitIds[$k4]]['Feed'][] = $feed['Feed'];
}
}
if ($feed['Feed']['source_format'] == 'misp') {
$pipe = $redis->multi(Redis::PIPELINE);
$eventUuidHitPosition = array();
$i = 0;
foreach ($objects as $k => $object) {
if (isset($object['Feed'])) {
foreach ($object['Feed'] as $currentFeed) {
if ($feed['Feed']['id'] == $currentFeed['id']) {
$eventUuidHitPosition[$i] = $k;
$i++;
if (in_array($object['type'], $this->Event->Attribute->getCompositeTypes())) {
$value = explode('|', $object['value']);
$redis->smembers('misp:feed_cache:event_uuid_lookup:' . md5($value[0]));
} else {
$redis->smembers('misp:feed_cache:event_uuid_lookup:' . md5($object['value']));
}
}
}
}
}
$mispFeedHits = $pipe->exec();
foreach ($mispFeedHits as $feedhitPos => $f) {
foreach ($f as $url) {
$urlParts = explode('/', $url);
if (empty($event['Feed'][$urlParts[0]]['event_uuids']) || !in_array($urlParts[1], $event['Feed'][$urlParts[0]]['event_uuids'])) {
$event['Feed'][$urlParts[0]]['event_uuids'][] = $urlParts[1];
}
foreach ($objects[$eventUuidHitPosition[$feedhitPos]]['Feed'] as $tempKey => $tempFeed) {
if ($tempFeed['id'] == $urlParts[0]) {
$objects[$eventUuidHitPosition[$feedhitPos]]['Feed'][$tempKey]['event_uuids'][] = $urlParts[1];
}
}
}
}
}
}
}
if ($redis === false) {
return $data;
}
if (!empty($event['Feed'])) {
$event['Feed'] = array_values($event['Feed']);
foreach ($data as $k => $v) {
$data[$k]['Server']['cache_timestamp'] = $redis->get('misp:server_cache_timestamp:' . $data[$k]['Server']['id']);
}
return $objects;
return $data;
}
}

View File

@ -117,15 +117,17 @@
</ul>
</li>
<?php if ($isAclSync || $isAdmin): ?>
<?php if ($isAclSync || $isAdmin || $hostOrgUser): ?>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<?php echo __('Sync Actions');?>
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="<?php echo $baseurl;?>/servers/index"><?php echo __('List Servers');?></a></li>
<?php if ($isSiteAdmin): ?>
<?php if ($isAclSync || $isAdmin): ?>
<li><a href="<?php echo $baseurl;?>/servers/index"><?php echo __('List Servers');?></a></li>
<?php endif; ?>
<?php if ($isSiteAdmin || $hostOrgUser): ?>
<li><a href="<?php echo $baseurl;?>/feeds/index"><?php echo __('List Feeds');?></a></li>
<?php endif;?>
</ul>

View File

@ -356,24 +356,42 @@
break;
case 'sync':
if ($menuItem === 'previewEvent' && $isSiteAdmin) : ?>
<li class="active"><?php echo $this->Html->link(__('Explore Remote Event'), array('controller' => 'servers', 'action' => 'previewEvent', h($server['Server']['id']), h($event['Event']['id']))); ?></li>
<li><?php echo $this->Form->postLink(__('Fetch This Event'), '/servers/pull/' . $server['Server']['id'] . '/' . $event['Event']['id'], null, __('Are you sure you want to fetch and save this event on your instance?', $this->Form->value('Server.id'))); ?></li>
<li><?php echo $this->Html->link(__('Explore Remote Server'), array('controller' => 'servers', 'action' => 'previewIndex', h($server['Server']['id']))); ?></li>
<?php endif;
if ($menuItem === 'previewIndex' && $isSiteAdmin) : ?>
<li class="active"><?php echo $this->Html->link(__('Explore Remote Server'), array('controller' => 'servers', 'action' => 'previewIndex', h($id))); ?></li>
<?php endif; ?>
<?php if ($menuItem === 'edit' && $isSiteAdmin): ?>
<li class="active"><?php echo $this->Html->link(__('Edit Server'), array('controller' => 'servers', 'action' => 'edit')); ?></li>
<li><?php echo $this->Form->postLink(__('Delete'), array('action' => 'delete', $this->Form->value('Server.id')), null, __('Are you sure you want to delete # %s?', $this->Form->value('Server.id'))); ?></li>
<li class="divider"></li>
<?php endif; ?>
<li id='liindex'><?php echo $this->Html->link(__('List Servers'), array('controller' => 'servers', 'action' => 'index'));?></li>
<?php if ($isSiteAdmin): ?>
<li id='liadd'><?php echo $this->Html->link(__('New Server'), array('controller' => 'servers', 'action' => 'add')); ?></li>
<?php endif;?>
<?php
if ($menuItem === 'previewEvent' && ($isSiteAdmin || $hostOrg)) {
echo sprintf(
'<li>%s</li><li class="active">%s</li>',
$this->Html->link(__('Explore Remote Server'), array('controller' => 'servers', 'action' => 'previewIndex', h($server['Server']['id']))),
$this->Html->link(__('Explore Remote Event'), array('controller' => 'servers', 'action' => 'previewEvent', h($server['Server']['id']), h($event['Event']['id'])))
);
}
if ($menuItem === 'previewEvent' && $isSiteAdmin) {
echo sprintf(
'<li>%s</li>',
$this->Form->postLink(__('Fetch This Event'), '/servers/pull/' . $server['Server']['id'] . '/' . $event['Event']['id'], null, __('Are you sure you want to fetch and save this event on your instance?', $this->Form->value('Server.id')))
);
}
if ($menuItem === 'previewIndex' && ($isSiteAdmin || $hostOrg)) {
echo sprintf(
'<li class="active">%s</li>',
$this->Html->link(__('Explore Remote Server'), array('controller' => 'servers', 'action' => 'previewIndex', h($id)))
);
}
if ($menuItem === 'edit' && $isSiteAdmin) {
echo sprintf(
'<li class="active">%s</li><li>%s</li><li class="divider"></li>',
$this->Html->link(__('Edit Server'), array('controller' => 'servers', 'action' => 'edit')),
$this->Form->postLink(__('Delete'), array('action' => 'delete', $this->Form->value('Server.id')), null, __('Are you sure you want to delete # %s?', $this->Form->value('Server.id')))
);
}
echo sprintf(
'<li id="liindex">%s</li>',
$this->Html->link(__('List Servers'), array('controller' => 'servers', 'action' => 'index'))
);
if ($isSiteAdmin) {
echo sprintf(
'<li id="liadd">%s</li>',
$this->Html->link(__('New Server'), array('controller' => 'servers', 'action' => 'add'))
);
}
break;
case 'admin':
@ -515,19 +533,54 @@
endif;
break;
case 'feeds': ?>
<li id='liindex'><a href="<?php echo $baseurl;?>/feeds/index"><?php echo __('List Feeds');?></a></li>
<li id='liadd'><a href="<?php echo $baseurl;?>/feeds/add"><?php echo __('Add Feed');?></a></li>
<li id='liadd'><a href="<?php echo $baseurl;?>/feeds/importFeeds"><?php echo __('Import Feeds from JSON');?></a></li>
<li id='licompare'><a href="<?php echo $baseurl;?>/feeds/compareFeeds"><?php echo __('Feed overlap analysis matrix');?></a></li>
<li id='liexport'><a href="<?php echo $baseurl;?>/feeds/index.json" download="feed_index.json"><?php echo __('Export Feed settings');?></a></li>
<?php if ($menuItem === 'edit'): ?>
<li class="active"><a href="#"><?php echo __('Edit Feed');?></a></li>
<?php elseif ($menuItem === 'previewIndex'): ?>
<li id='lipreviewIndex'><a href="<?php echo $baseurl;?>/feeds/previewIndex/<?php echo h($feed['Feed']['id']); ?>"><?php echo __('PreviewIndex');?></a></li>
<?php elseif ($menuItem === 'previewEvent'): ?>
<li id='lipreviewEvent'><a href="<?php echo $baseurl;?>/feeds/previewEvent/<?php echo h($feed['Feed']['id']); ?>/<?php echo h($id);?>"><?php echo __('PreviewEvent');?></a></li>
<?php endif;
case 'feeds':
echo sprintf(
'<li id="liindex"><a href="%s/feeds/index">%s</a></li>',
$baseurl,
__('List Feeds')
);
if ($isSiteAdmin) {
echo sprintf(
'<li id="liadd"><a href="%s/feeds/add">%s</a></li>',
$baseurl,
__('Add Feed')
);
echo sprintf(
'<li id="liimport"><a href="%s/feeds/importFeeds">%s</a></li>',
$baseurl,
__('Import Feeds from JSON')
);
}
echo sprintf(
'<li id="licompare"><a href="%s/feeds/compareFeeds">%s</a></li>',
$baseurl,
__('Feed overlap analysis matrix')
);
echo sprintf(
'<li id="liexport"><a href="%s/feeds/index.json" download="feed_index.json">%s</a></li>',
$baseurl,
__('Export Feed settings')
);
if ($isSiteAdmin) {
if ($menuItem === 'edit') {
echo '<li class="active"><a href="#">' . __('Edit Feed') . '</a></li>';
} else if ($menuItem === 'previewIndex') {
echo sprintf(
'<li id="lipreviewIndex"><a href="%s/feeds/previewIndex/%s"></a></li>',
$baseurl,
h($feed['Feed']['id']),
__('PreviewIndex')
);
} else if ($menuItem === 'previewEvent') {
echo sprintf(
'<li id="lipreviewEvent"><a href="%s/feeds/previewEvent/%s/%s">%s</a></li>',
$baseurl,
h($feed['Feed']['id']),
h($id),
__('PreviewEvent')
);
}
}
break;
case 'news': ?>

View File

@ -21,7 +21,7 @@
?>
<th>
<div data-toggle="popover" data-content="<?php echo $popover; ?>" data-trigger="hover">
<?php echo h($item['Feed']['id']); ?>
<?php echo (empty($item['Feed']['is_misp_server']) ? 'F' : 'S') . h($item['Feed']['id']); ?>
</div>
</th>
<?php
@ -38,7 +38,15 @@
<tr>
<td class="short">
<div data-toggle="popover" data-content="<?php echo $popover;?>" data-trigger="hover">
<?php echo h($item['Feed']['id']) . ' ' . h($item['Feed']['name']); ?>&nbsp;
<?php
echo sprintf(
'%s%s %s%s',
empty($item['Feed']['is_misp_server']) ? 'Feed #' : 'Server #',
h($item['Feed']['id']),
empty($item['Feed']['is_misp_server']) ? '' : '(<span class="blue bold">MISP</span>) ',
h($item['Feed']['name'])
);
?>
</div>
</td>
<?php

View File

@ -196,7 +196,7 @@ foreach ($feeds as $item):
else:
echo __('Not cached');
endif;
if ($item['Feed']['caching_enabled']):
if ($item['Feed']['caching_enabled'] && $isSiteAdmin):
?>
<a href="<?php echo $baseurl;?>/feeds/cacheFeeds/<?php echo h($item['Feed']['id']); ?>" title="Cache feed"><span class="icon-download-alt"></span></a>
<?php
@ -206,12 +206,14 @@ foreach ($feeds as $item):
<td class="short action-links">
<?php
echo $this->Html->link('', array('action' => 'previewIndex', $item['Feed']['id']), array('class' => 'icon-search', 'title' => __('Explore the events remotely')));
if (!isset($item['Feed']['event_error'])) {
if (!isset($item['Feed']['event_error']) && $isSiteAdmin) {
if ($item['Feed']['enabled']) echo $this->Html->link('', array('action' => 'fetchFromFeed', $item['Feed']['id']), array('class' => 'icon-download', 'title' => __('Fetch all events')));
}
if ($isSiteAdmin):
?>
<a href="<?php echo $baseurl;?>/feeds/edit/<?php echo h($item['Feed']['id']); ?>"><span class="icon-edit" title="Edit">&nbsp;</span></a>
<?php echo $this->Form->postLink('', array('action' => 'delete', h($item['Feed']['id'])), array('class' => 'icon-trash', 'title' => __('Delete')), __('Are you sure you want to permanently remove the feed (%s)?', h($item['Feed']['name']))); ?>
<a href="<?php echo $baseurl;?>/feeds/edit/<?php echo h($item['Feed']['id']); ?>"><span class="icon-edit" title="Edit">&nbsp;</span></a>
<?php echo $this->Form->postLink('', array('action' => 'delete', h($item['Feed']['id'])), array('class' => 'icon-trash', 'title' => __('Delete')), __('Are you sure you want to permanently remove the feed (%s)?', h($item['Feed']['name']))); ?>
<?php endif; ?>
<a href="<?php echo $baseurl;?>/feeds/view/<?php echo h($item['Feed']['id']); ?>.json" title="<?php echo __('Download feed metadata as JSON');?>" download><span class="fa fa-cloud-download black"></span></a>
</td>
</tr><?php

View File

@ -62,7 +62,7 @@
</td>
<td ondblclick="document.location.href ='<?php echo $eventViewURL . h($uuid);?>'" class="short"><?php echo h($event['timestamp']); ?></td>
<td class="short action-links">
<?php if ($feed['Feed']['enabled']) echo $this->Form->postLink('', '/feeds/getEvent/' . $id . '/' . $uuid, array('class' => 'icon-download', 'title' => 'Fetch the event'), __('Are you sure you want to fetch and save this event on your instance?', $this->Form->value('Feed.id'))); ?>
<?php if ($feed['Feed']['enabled'] && $isSiteAdmin) echo $this->Form->postLink('', '/feeds/getEvent/' . $id . '/' . $uuid, array('class' => 'icon-download', 'title' => 'Fetch the event'), __('Are you sure you want to fetch and save this event on your instance?', $this->Form->value('Feed.id'))); ?>
<a href='<?php echo $eventViewURL . h($uuid);?>' class = "icon-list-alt" title = "<?php echo __('View');?>"></a>
</td>
</tr>

View File

@ -73,7 +73,41 @@ foreach ($servers as $server):
<td><span class="<?php echo ($server['Server']['internal']? 'icon-ok' : 'icon-remove'); ?>" title="<?php echo ($server['Server']['internal']? __('Internal instance that ignores distribution level degradation *WARNING: Only use this setting if you have several internal instances and the sync link is to an internal extension of the current MISP community*') : __('Normal sync link to an external MISP instance. Distribution degradation will follow the normal rules.')); ?>"></span></td>
<td><span class="<?php echo ($server['Server']['push']? 'icon-ok' : 'icon-remove'); ?>"></span><span class="short <?php if (!$server['Server']['push'] || empty($ruleDescription['push'])) echo "hidden"; ?>" data-toggle="popover" title="Distribution List" data-content="<?php echo $ruleDescription['push']; ?>"> (<?php echo __('Rules');?>)</span></td>
<td><span class="<?php echo ($server['Server']['pull']? 'icon-ok' : 'icon-remove'); ?>"></span><span class="short <?php if (!$server['Server']['pull'] || empty($ruleDescription['pull'])) echo "hidden"; ?>" data-toggle="popover" title="Distribution List" data-content="<?php echo $ruleDescription['pull']; ?>"> (<?php echo __('Rules');?>)</span></td>
<td><span class="<?php echo ($server['Server']['caching_enabled']? 'icon-ok' : 'icon-remove'); ?>"></span></td>
<td>
<?php
if ($server['Server']['caching_enabled']) {
if (!empty($server['Server']['cache_timestamp'])) {
$units = array('m', 'h', 'd');
$intervals = array(60, 60, 24);
$unit = 's';
$last = time() - $server['Server']['cache_timestamp'];
foreach ($units as $k => $v) {
if ($last > $intervals[$k]) {
$unit = $v;
$last = floor($last / $intervals[$k]);
} else {
break;
}
}
echo sprintf(
'<span class="blue bold">%s%s%s</span> %s',
__('Age: '),
$last,
$unit,
'<span class="icon-ok"></span>'
);
} else {
echo sprintf(
'<span class="red bold">%s</span> %s',
__('Not cached'),
'<span class="icon-ok"></span>'
);
}
} else {
echo '<span class="icon-remove"></span>';
}
?>
</td>
<td class="short"><span class="<?php echo ($server['Server']['unpublish_event'] ? 'icon-ok' : 'icon-remove'); ?>"></span></td>
<td class="short"><span class="<?php echo ($server['Server']['publish_without_email'] ? 'icon-ok' : 'icon-remove'); ?>"></span></td>
<td><?php echo h($server['Server']['url']); ?>&nbsp;</td>

View File

@ -38,7 +38,7 @@ malware_galaxies_list = ('android', 'banker', 'stealer', 'backdoor', 'ransomware
threat_actor_galaxies_list = ('threat-actor', 'microsoft-activity-group')
tool_galaxies_list = ('botnet', 'rat', 'exploit-kit', 'tds', 'tool', 'mitre-tool',
'mitre-enterprise-attack-tool', 'mitre-mobile-attack-tool')
_MISP_event_tags = ('Threat-Report', 'misp:tool="misp2stix2"')
_MISP_event_tags = ['Threat-Report', 'misp:tool="misp2stix2"']
class StixBuilder():
def __init__(self):
@ -68,21 +68,16 @@ class StixBuilder():
external_refs = [self.__parse_link(link) for link in self.links]
report_args = {'type': 'report', 'id': self.report_id, 'name': self.misp_event['info'],
'created_by_ref': self.identity_id, 'created': self.misp_event['date'],
'published': self.get_datetime_from_timestamp(self.misp_event['publish_timestamp']),
'labels': []}
'published': self.get_datetime_from_timestamp(self.misp_event['publish_timestamp'])}
labels = _MISP_event_tags
if self.misp_event.get('Tag'):
markings = []
for tag in self.misp_event['Tag']:
tag_name = tag['name']
if tag_name in _MISP_event_tags:
report_args['labels'].append(tag_name)
else:
markings.append(self.markings[tag_name]['id'] if tag_name in self.markings else self.create_marking(tag_name))
name = tag['name']
markings.append(name) if name.startswith('tlp:') else labels.append(name)
if markings:
report_args['object_marking_refs'] = markings
for label in _MISP_event_tags:
if label not in report_args['labels']:
report_args['labels'].append(label)
report_args['object_marking_refs'] = self.handle_tags(markings)
report_args['labels'] = labels
if external_refs:
report_args['external_references'] = external_refs
self.add_all_markings()
@ -417,15 +412,14 @@ class StixBuilder():
def add_custom(self, attribute):
custom_object_id = "x-misp-object--{}".format(attribute['uuid'])
custom_object_type = "x-misp-object-{}".format(attribute['type'].replace('|', '-').lower())
labels = self.create_labels(attribute)
labels, markings = self.create_labels(attribute)
custom_object_args = {'id': custom_object_id, 'x_misp_category': attribute['category'], 'labels': labels,
'x_misp_timestamp': self.get_datetime_from_timestamp(attribute['timestamp']),
'x_misp_value': attribute['value'], 'created_by_ref': self.identity_id}
if attribute.get('comment'):
custom_object_args['x_misp_comment'] = attribute['comment']
markings = []
if attribute.get('Tag'):
markings = self.handle_tags(attribute['Tag'])
if markings:
markings = self.handle_tags(markings)
custom_object_args['object_marking_refs'] = markings
@CustomObject(custom_object_type, [('id', properties.StringProperty(required=True)),
('x_misp_timestamp', properties.StringProperty(required=True)),
@ -445,13 +439,13 @@ class StixBuilder():
def add_identity(self, attribute):
identity_id = "identity--{}".format(attribute['uuid'])
name = attribute['value']
labels = self.create_labels(attribute)
labels, markings = self.create_labels(attribute)
identity_args = {'id': identity_id, 'type': identity, 'name': name, 'labels': labels,
'identity_class': 'individual', 'created_by_ref': self.identity_id}
if attribute.get('comment'):
identity_args['description'] = attribute['comment']
if attribute.get('Tag'):
identity_args['object_marking_refs'] = self.handle_tags(attribute['Tag'])
if markings:
identity_args['object_marking_refs'] = self.handle_tags(markings)
identity = Identity(**identity_args, interoperability=True)
self.append_object(identity, identity_id)
@ -461,7 +455,7 @@ class StixBuilder():
self.parse_galaxies(attribute['Galaxy'], indicator_id)
category = attribute['category']
killchain = self.create_killchain(category)
labels = self.create_labels(attribute)
labels, markings = self.create_labels(attribute)
attribute_value = attribute['value'] if attribute_type != "AS" else self.define_attribute_value(attribute['value'], attribute['comment'])
pattern = mispTypesMapping[attribute_type]['pattern'](attribute_type, attribute_value, attribute['data']) if attribute.get('data') else self.define_pattern(attribute_type, attribute_value)
indicator_args = {'id': indicator_id, 'type': 'indicator', 'labels': labels, 'kill_chain_phases': killchain,
@ -473,8 +467,8 @@ class StixBuilder():
break
if attribute.get('comment'):
indicator_args['description'] = attribute['comment']
if attribute.get('Tag'):
indicator_args['object_marking_refs'] = self.handle_tags(attribute['Tag'])
if markings:
indicator_args['object_marking_refs'] = self.handle_tags(markings)
indicator = Indicator(**indicator_args, interoperability=True)
self.append_object(indicator, indicator_id)
@ -495,14 +489,14 @@ class StixBuilder():
observed_data_id = "observed-data--{}".format(attribute['uuid'])
self.parse_galaxies(attribute['Galaxy'], observed_data_id)
timestamp = self.get_datetime_from_timestamp(attribute['timestamp'])
labels = self.create_labels(attribute)
labels, markings = self.create_labels(attribute)
attribute_value = attribute['value'] if attribute_type != "AS" else self.define_attribute_value(attribute['value'], attribute['comment'])
observable = mispTypesMapping[attribute_type]['observable'](attribute_type, attribute_value, attribute['data']) if attribute.get('data') else self.define_observable(attribute_type, attribute_value)
observed_data_args = {'id': observed_data_id, 'type': 'observed-data', 'number_observed': 1,
'first_observed': timestamp, 'last_observed': timestamp, 'labels': labels,
'created_by_ref': self.identity_id, 'objects': observable}
if attribute.get('Tag'):
observed_data_args['object_marking_refs'] = self.handle_tags(attribute['Tag'])
if markings:
observed_data_args['object_marking_refs'] = self.handle_tags(markings)
observed_data = ObservedData(**observed_data_args, interoperability=True)
self.append_object(observed_data, observed_data_id)
@ -522,12 +516,12 @@ class StixBuilder():
vulnerability_id = "vulnerability--{}".format(attribute['uuid'])
name = attribute['value']
vulnerability_data = [mispTypesMapping['vulnerability']['vulnerability_args'](name)]
labels = self.create_labels(attribute)
labels, markings = self.create_labels(attribute)
vulnerability_args = {'id': vulnerability_id, 'type': 'vulnerability',
'name': name, 'external_references': vulnerability_data,
'created_by_ref': self.identity_id, 'labels': labels}
if attribute.get('Tag'):
vulnerability_args['object_marking_refs'] = self.handle_tags(attribute['Tag'])
if markings:
vulnerability_args['object_marking_refs'] = self.handle_tags(markings)
vulnerability = Vulnerability(**vulnerability_args, interoperability=True)
self.append_object(vulnerability, vulnerability_id)
@ -654,9 +648,15 @@ class StixBuilder():
@staticmethod
def create_labels(attribute):
return ['misp:type="{}"'.format(attribute['type']),
'misp:category="{}"'.format(attribute['category']),
'misp:to_ids="{}"'.format(attribute['to_ids'])]
labels = ['misp:type="{}"'.format(attribute['type']),
'misp:category="{}"'.format(attribute['category']),
'misp:to_ids="{}"'.format(attribute['to_ids'])]
markings = []
if attribute.get('Tag'):
for tag in attribute['Tag']:
name = tag['name']
markings.append(name) if name.startswith('tlp:') else labels.append(name)
return labels, markings
@staticmethod
def create_object_labels(name, category, to_ids):
@ -667,11 +667,9 @@ class StixBuilder():
def create_marking(self, tag):
id = 'marking-definition--%s' % uuid.uuid4()
tag_list = tag.split(':')
namespace, predicate = tag_list if len(tag_list) == 2 else (tag_list[0], ":".join(tag_list[1:]))
definition_type, marking = (namespace, predicate) if namespace == 'tlp' else ('statement', self._parse_tag(namespace, predicate))
definition_type, definition = tag.split(':')
self.markings[tag] = {'type': 'marking-definition', 'id': id, 'definition_type': definition_type,
'definition': {definition_type: marking}}
'definition': {definition_type: definition}}
return id
@staticmethod
@ -720,11 +718,7 @@ class StixBuilder():
return "Undefined name"
def handle_tags(self, tags):
markings = []
for tag in tags:
tag_name = tag['name']
markings.append(self.markings[tag_name]['id'] if tag_name in self.markings else self.create_marking(tag_name))
return markings
return [self.markings[tag]['id'] if tag in self.markings else self.create_marking(tag) for tag in tags]
def resolve_asn_observable(self, attributes, object_id):
asn = objectsMapping['asn']['observable']

View File

@ -911,13 +911,7 @@ class StixFromMISPParser(StixParser):
def parse_marking(marking):
marking_type = marking.definition_type
tag = getattr(marking.definition, marking_type)
if marking_type == 'tlp':
return "{}:{}".format(marking_type, tag)
if TAG_REGEX.match(tag):
predicate, value = tag.split(' = ')
namespace, predicate = predicate.split(') ')
return '{}:{}="{}"'.format(namespace[1:], predicate, value)
return ":".join(tag.split(' = '))
return "{}:{}".format(marking_type, tag)
@staticmethod
def parse_pattern(pattern):