mirror of https://github.com/MISP/MISP
Merge branch '2.4' into 1501
commit
a599ec24f7
|
@ -61,3 +61,4 @@
|
|||
/app/tmp/cached_exports/csv_all/*
|
||||
/app/tmp/cached_exports/csv_sig/*
|
||||
*.swp
|
||||
*.iml
|
||||
|
|
|
@ -327,6 +327,31 @@ class EventShell extends AppShell
|
|||
$this->Job->saveField('date_modified', date("y-m-d H:i:s"));
|
||||
}
|
||||
|
||||
public function cachebro()
|
||||
{
|
||||
$broHeader = "#fields indicator\tindicator_type\tmeta.source\tmeta.url\tmeta.do_notice\tmeta.if_in\n";
|
||||
$userId = $this->args[0];
|
||||
$user = $this->User->getAuthUser($userId);
|
||||
$id = $this->args[1];
|
||||
$this->Job->id = $id;
|
||||
$format = $this->args[2];
|
||||
$this->Job->saveField('progress', 1);
|
||||
$types = array('ip', 'email', 'domain', 'filename', 'filehash', 'certhash', 'software', 'url'); //Bro types
|
||||
$typeCount = count($types);
|
||||
$dir = new Folder(APP . DS . '/tmp/cached_exports/' . $format, true, 0750);
|
||||
if ($user['Role']['perm_site_admin']) {
|
||||
$zipname = DS . 'misp.bro.ADMIN.intel.zip';
|
||||
} else {
|
||||
$zipname = DS . 'misp.bro.' . $user['Organisation']['name'] . '.intel.zip';
|
||||
}
|
||||
$tmpZipname = $this->Attribute->brozip($user, false, false, false, false, false, false, $id);
|
||||
rename($tmpZipname[0] . $tmpZipname[1], $dir->pwd() . $zipname);
|
||||
$folder = new Folder($tmpZipname[0]);
|
||||
$folder->delete();
|
||||
$this->Job->saveField('progress', 100);
|
||||
$this->Job->saveField('message', 'Job done.');
|
||||
}
|
||||
|
||||
public function alertemail() {
|
||||
$userId = $this->args[0];
|
||||
$processId = $this->args[1];
|
||||
|
|
|
@ -1089,7 +1089,7 @@ class AttributesController extends AppController {
|
|||
$this->set('categoryDefinitions', $this->Attribute->categoryDefinitions);
|
||||
// reset the paginate_conditions
|
||||
$this->Session->write('paginate_conditions',array());
|
||||
if ($this->request->is('post') && ($this->request->here == $fullAddress)) {
|
||||
if ($this->request->is('post')) {
|
||||
$keyword = $this->request->data['Attribute']['keyword'];
|
||||
$keyword2 = $this->request->data['Attribute']['keyword2'];
|
||||
$tags = $this->request->data['Attribute']['tags'];
|
||||
|
@ -1850,6 +1850,61 @@ class AttributesController extends AppController {
|
|||
$this->render('/Attributes/rpz');
|
||||
}
|
||||
|
||||
public function bro($key='download', $type='all', $tags=false, $eventId=false, $allowNonIDS=false, $from=false, $to=false, $last=false) {
|
||||
if ($this->request->is('post')) {
|
||||
if ($this->request->input('json_decode', true)) {
|
||||
$data = $this->request->input('json_decode', true);
|
||||
} else {
|
||||
$data = $this->request->data;
|
||||
}
|
||||
if (!empty($data) && !isset($data['request'])) {
|
||||
$data = array('request' => $data);
|
||||
}
|
||||
$paramArray = array('type', 'tags', 'eventId', 'allowNonIDS', 'from', 'to', 'last');
|
||||
foreach ($paramArray as $p) {
|
||||
if (isset($data['request'][$p])) ${$p} = $data['request'][$p];
|
||||
}
|
||||
}
|
||||
$simpleFalse = array('type', 'tags', 'eventId', 'allowNonIDS', 'from', 'to', 'last');
|
||||
foreach ($simpleFalse as $sF) {
|
||||
if (!is_array(${$sF}) && (${$sF} === 'null' || ${$sF} == '0' || ${$sF} === false || strtolower(${$sF}) === 'false')) ${$sF} = false;
|
||||
}
|
||||
if ($type !== 'null' || $type !== '0' || $type !== 'false') {
|
||||
if ($from) $from = $this->Attribute->Event->dateFieldCheck($from);
|
||||
if ($to) $to = $this->Attribute->Event->dateFieldCheck($to);
|
||||
if ($last) $last = $this->Attribute->Event->resolveTimeDelta($last);
|
||||
if ($key != 'download') {
|
||||
// check if the key is valid -> search for users based on key
|
||||
$user = $this->checkAuthUser($key);
|
||||
if (!$user) {
|
||||
throw new UnauthorizedException('This authentication key is not authorized to be used for exports. Contact your administrator.');
|
||||
}
|
||||
} else {
|
||||
if (!$this->Auth->user('id')) {
|
||||
throw new UnauthorizedException('You have to be logged in to do that.');
|
||||
}
|
||||
}
|
||||
$filename = 'misp.' . $type . '.intel';
|
||||
if ($eventId) {
|
||||
$filename = 'misp.' . $type . '.event_' . $eventId . '.intel';
|
||||
}
|
||||
if ($type != 'all') {
|
||||
$responseFile = implode(PHP_EOL, $this->Attribute->bro($this->Auth->user(), $type, $tags, $eventId, $allowNonIDS, $from, $to, $last)) . PHP_EOL;
|
||||
$this->response->body($responseFile);
|
||||
$this->response->type('txt');
|
||||
} else {
|
||||
$tmpZipname = $this->Attribute->brozip($this->Auth->user(), $tags, $eventId, $allowNonIDS, $from, $to, $last);
|
||||
$this->response->body(file_get_contents($tmpZipname[0] . $tmpZipname[1]));
|
||||
$this->response->type('zip');
|
||||
$folder = new Folder($tmpZipname[0]);
|
||||
$folder->delete();
|
||||
$filename .= '.zip';
|
||||
}
|
||||
$this->response->download($filename);
|
||||
return $this->response;
|
||||
}
|
||||
}
|
||||
|
||||
public function reportValidationIssuesAttributes($eventId = false) {
|
||||
// TODO improve performance of this function by eliminating the additional SQL query per attribute
|
||||
// search for validation problems in the attributes
|
||||
|
|
|
@ -61,7 +61,6 @@ class IOCExportComponent extends Component {
|
|||
);
|
||||
|
||||
private function __frameComposite($attribute) {
|
||||
$types = explode('|', $attribute['type']);
|
||||
$values = explode('|', $attribute['value']);
|
||||
$this->final[] = ' <Indicator operator="AND" id="' . h($attribute['uuid']) . '">';
|
||||
$this->__frameIndicator($this->mapping['composite'][$attribute['type']][0], $attribute['uuid'], $values[0], true);
|
||||
|
@ -70,7 +69,6 @@ class IOCExportComponent extends Component {
|
|||
}
|
||||
|
||||
private function __frameIndicator($mapping, $uuid, $value, $extraIndent = false) {
|
||||
$indent = " ";
|
||||
$padding = 6;
|
||||
if ($extraIndent) {
|
||||
$padding = 8;
|
||||
|
|
|
@ -4,10 +4,6 @@ App::uses('AppController', 'Controller');
|
|||
class EventDelegationsController extends AppController {
|
||||
public $components = array('Session', 'RequestHandler');
|
||||
|
||||
public function beforeFilter() {
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
public $paginate = array(
|
||||
'limit' => 60,
|
||||
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
|
||||
|
|
|
@ -1483,6 +1483,17 @@ class EventsController extends AppController {
|
|||
if (!$this->userRole['perm_auth']) {
|
||||
$this->redirect(array('controller' => 'events', 'action' => 'index'));
|
||||
}
|
||||
App::uses('BroExport', 'Export');
|
||||
$export = new BroExport();
|
||||
$temp = $export->mispTypes;
|
||||
$broTypes = array('all' => 'All types listed below.');
|
||||
foreach ($temp as $broType => $mispTypes) {
|
||||
foreach ($mispTypes as $mT) {
|
||||
$broTypes[$broType][] = $mT[0];
|
||||
}
|
||||
$broTypes[$broType] = implode(', ', $broTypes[$broType]);
|
||||
}
|
||||
$this->set('broTypes', $broTypes);
|
||||
// generate the list of Attribute types
|
||||
$this->loadModel('Attribute');
|
||||
$this->set('sigTypes', array_keys($this->Attribute->typeDefinitions));
|
||||
|
@ -1719,7 +1730,6 @@ class EventsController extends AppController {
|
|||
if ($last) $last = $this->Event->resolveTimeDelta($last);
|
||||
// backwards compatibility, swap key and format
|
||||
if ($format != 'snort' && $format != 'suricata') {
|
||||
$key = $format;
|
||||
$format = 'suricata'; // default format
|
||||
}
|
||||
$this->response->type('txt'); // set the content type
|
||||
|
@ -3150,6 +3160,12 @@ class EventsController extends AppController {
|
|||
'requiresPublished' => true,
|
||||
'checkbox' => false,
|
||||
),
|
||||
'bro' => array(
|
||||
'url' => '/attributes/bro/download/all/false/' . $id,
|
||||
'text' => 'Download Bro rules',
|
||||
'requiresPublished' => true,
|
||||
'checkbox' => false
|
||||
),
|
||||
'text' => array(
|
||||
'url' => '/attributes/text/download/all/false/' . $id,
|
||||
'text' => 'Export all attribute values as a text file',
|
||||
|
|
|
@ -4,10 +4,6 @@ App::uses('AppController', 'Controller');
|
|||
class FavouriteTagsController extends AppController {
|
||||
public $components = array('Session', 'RequestHandler');
|
||||
|
||||
public function beforeFilter() {
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
public $paginate = array(
|
||||
'limit' => 60,
|
||||
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
|
||||
|
|
|
@ -12,10 +12,6 @@ class JobsController extends AppController {
|
|||
),
|
||||
);
|
||||
|
||||
public function beforeFilter() {
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
public function index($queue = false) {
|
||||
if (!$this->_isSiteAdmin()) throw new MethodNotAllowedException();
|
||||
if (!Configure::read('MISP.background_jobs')) throw new NotFoundException('Background jobs are not enabled on this instance.');
|
||||
|
|
|
@ -4,10 +4,6 @@ App::uses('AppController', 'Controller');
|
|||
class NewsController extends AppController {
|
||||
public $components = array('Session', 'RequestHandler');
|
||||
|
||||
public function beforeFilter() {
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
public $paginate = array(
|
||||
'limit' => 5,
|
||||
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
|
||||
|
@ -17,7 +13,6 @@ class NewsController extends AppController {
|
|||
);
|
||||
|
||||
public function index() {
|
||||
$this->News->bindModel(array('belongsTo' => array('User' => array('className' => 'User'))));
|
||||
$this->paginate['contain'] = array('User' => array('fields' => array('User.email')));
|
||||
$newsItems = $this->paginate();
|
||||
$this->loadModel('User');
|
||||
|
|
|
@ -20,10 +20,6 @@ class PostsController extends AppController {
|
|||
'limit' => 60,
|
||||
);
|
||||
|
||||
public function beforeFilter() {
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
// Find the thread_id and post_id in advance. If a user clicks post comment on the event view, send the event's related thread's ID
|
||||
// Usage:
|
||||
// /posts/add : Creates new thread with the added post as the first post. Title set by user
|
||||
|
|
|
@ -13,10 +13,6 @@ class RegexpController extends AppController {
|
|||
)
|
||||
);
|
||||
|
||||
public function beforeFilter() {
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
public function admin_add() {
|
||||
$this->loadModel('Attribute');
|
||||
$types = array_keys($this->Attribute->typeDefinitions);
|
||||
|
|
|
@ -26,10 +26,6 @@ class RolesController extends AppController {
|
|||
)
|
||||
);
|
||||
|
||||
public function beforeFilter() {
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
public function view($id = null) {
|
||||
$this->Role->id = $id;
|
||||
if (!$this->Role->exists()) {
|
||||
|
|
|
@ -23,10 +23,6 @@ class TagsController extends AppController {
|
|||
|
||||
public $helpers = array('TextColour');
|
||||
|
||||
public function beforeFilter() { // TODO REMOVE
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
public function index($favouritesOnly = false) {
|
||||
$this->loadModel('Event');
|
||||
$this->loadModel('Taxonomy');
|
||||
|
@ -258,12 +254,6 @@ class TagsController extends AppController {
|
|||
'fields' => array('Tag.id', 'Tag.colour', 'Tag.name'),
|
||||
));
|
||||
$this->set('tags', $tags);
|
||||
$tags = $this->Tag->find('all', array('recursive' => -1, 'order' => array('Tag.name ASC')));
|
||||
$tagNames = array('None');
|
||||
foreach ($tags as $k => $v) {
|
||||
$tagNames[$v['Tag']['id']] = $v['Tag']['name'];
|
||||
}
|
||||
$this->set('allTags', $tagNames);
|
||||
$event = $this->Tag->EventTag->Event->find('first', array(
|
||||
'recursive' => -1,
|
||||
'fields' => array('Event.id', 'Event.orgc_id', 'Event.org_id', 'Event.user_id'),
|
||||
|
|
|
@ -12,10 +12,6 @@ class TasksController extends AppController {
|
|||
)
|
||||
);
|
||||
|
||||
public function beforeFilter() {
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
public function index() {
|
||||
if (!$this->_isSiteAdmin()) throw new MethodNotAllowedException();
|
||||
if (!Configure::read('MISP.background_jobs')) throw new NotFoundException('Background jobs are not enabled on this instance.');
|
||||
|
|
|
@ -4,10 +4,6 @@ App::uses('AppController', 'Controller');
|
|||
class TaxonomiesController extends AppController {
|
||||
public $components = array('Session', 'RequestHandler');
|
||||
|
||||
public function beforeFilter() {
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
public $paginate = array(
|
||||
'limit' => 60,
|
||||
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
|
||||
|
|
|
@ -16,10 +16,6 @@ class ThreadsController extends AppController {
|
|||
'limit' => 60,
|
||||
);
|
||||
|
||||
public function beforeFilter() {
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
public function viewEvent($id) {
|
||||
$this->loadModel('Event');
|
||||
$result = $this->Event->fetchEvent($this->Auth->user(), array('eventid' => $id));
|
||||
|
|
|
@ -4,10 +4,6 @@ App::uses('AppController', 'Controller');
|
|||
class WarninglistsController extends AppController {
|
||||
public $components = array('Session', 'RequestHandler');
|
||||
|
||||
public function beforeFilter() {
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
public $paginate = array(
|
||||
'limit' => 60,
|
||||
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
|
||||
|
|
|
@ -16,10 +16,6 @@ class WhitelistsController extends AppController {
|
|||
)
|
||||
);
|
||||
|
||||
public function beforeFilter() { // TODO REMOVE
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
public function admin_add() {
|
||||
if (!$this->userRole['perm_regexp_access']) $this->redirect(array('controller' => 'regexp', 'action' => 'index', 'admin' => false));
|
||||
$this->AdminCrud->adminAdd();
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
|
||||
class BroExport {
|
||||
|
||||
public $rules = array();
|
||||
|
||||
public $header = "#fields indicator\tindicator_type\tmeta.source\tmeta.url\tmeta.do_notice\tmeta.if_in";
|
||||
|
||||
// mapping from misp attribute type to the bro intel type
|
||||
// alternative mechanisms are:
|
||||
// - alternate: array containing a detection regex and a replacement bro type
|
||||
// - composite: for composite misp attributes (domain|ip), use the provided bro type if the second value is queried
|
||||
// - replace: run a replacement regex on the value before generating the bro rule
|
||||
private $mapping = array(
|
||||
'ip-dst' => array('brotype' => 'ADDR', 'alternate' => array('#/#', 'SUBNET')),
|
||||
'ip-src' => array('brotype' => 'ADDR', 'alternate' => array('#/#', 'SUBNET')),
|
||||
'email-src' => array('brotype' => 'EMAIL'),
|
||||
'email-dst' => array('brotype' => 'EMAIL'),
|
||||
'email-attachment' => array('brotype' => 'FILE_NAME'),
|
||||
'filename' => array('brotype' => 'FILE_NAME'),
|
||||
'hostname' => array('brotype' => 'DOMAIN'),
|
||||
'domain' => array('brotype' => 'DOMAIN'),
|
||||
'domain|ip' => array('brotype' => 'DOMAIN', 'composite' => 'ADDR'),
|
||||
'url' => array('brotype' => 'URL', 'replace' => array('#^https?://#', '')),
|
||||
'user-agent' => array('brotype' => 'SOFTWARE'),
|
||||
'md5' => array('brotype' => 'FILE_HASH'),
|
||||
'malware-sample' => array('brotype' => 'FILE_NAME', 'composite' => 'FILE_HASH'),
|
||||
'filename|md5' => array('brotype' => 'FILE_NAME', 'composite' => 'FILE_HASH'),
|
||||
'sha1' => array('brotype' => 'FILE_HASH'),
|
||||
'filename|sha1' => array('brotype' => 'FILE_NAME', 'composite' => 'FILE_HASH'),
|
||||
'sha256' => array('brotype' => 'FILE_HASH'),
|
||||
'filename|sha256' => array('brotype' => 'FILE_NAME', 'composite' => 'FILE_HASH'),
|
||||
'x509-fingerprint-sha1' => array('brotype' => 'CERT_HASH'),
|
||||
);
|
||||
|
||||
// export group to misp type mapping
|
||||
// the mapped type is in an array format, first value being the misp type, second being the value field used
|
||||
public $mispTypes = array(
|
||||
'ip' => array(
|
||||
array('ip-src', 1),
|
||||
array('ip-dst', 1),
|
||||
array('domain|ip', 2)
|
||||
),
|
||||
'url' => array(
|
||||
array('url', 1)
|
||||
),
|
||||
'domain' => array(
|
||||
array('hostname', 1),
|
||||
array('domain', 1),
|
||||
array('domain|ip', 1)
|
||||
),
|
||||
'email' => array(
|
||||
array('email-src', 1),
|
||||
array('email-dst', 1)
|
||||
),
|
||||
'filename' => array(
|
||||
array('filename', 1),
|
||||
array('email-attachment', 1),
|
||||
array('attachment', 1),
|
||||
array('filename|md5', 1),
|
||||
array('filename|sha1', 1),
|
||||
array('filename|sha256', 1),
|
||||
array('malware-sample', 1)
|
||||
),
|
||||
'filehash' => array(
|
||||
array('md5', 1),
|
||||
array('sha1', 1),
|
||||
array('sha256', 1),
|
||||
array('filename|md5', 2),
|
||||
array('filename|sha1', 2),
|
||||
array('filename|sha256', 2),
|
||||
array('malware-sample', 2)
|
||||
),
|
||||
'certhash' => array(
|
||||
array('x509-fingerprint-sha1', 1)
|
||||
),
|
||||
'software' => array(
|
||||
array('user-agent', 1)
|
||||
)
|
||||
);
|
||||
|
||||
private $whitelist = null;
|
||||
|
||||
public function export($items, $orgs, $valueField, $intel, $whitelist, $instanceString) {
|
||||
//For bro format organisation
|
||||
$orgsName = array();
|
||||
// generate the rules
|
||||
foreach ($items as $item) {
|
||||
if (!isset($orgs[$item['Event']['orgc_id']])) {
|
||||
continue;
|
||||
} else {
|
||||
$orgName = $instanceString . ' (' . $item['Event']['uuid'] . ')' . ' - ' . $orgs[$item['Event']['orgc_id']];
|
||||
}
|
||||
$ruleFormatReference = Configure::read('MISP.baseurl') . '/events/view/' . $item['Event']['id'];
|
||||
$ruleFormat = "%s\t%s\t" . $orgName . "\t" . $ruleFormatReference . "\t%s\t%s";
|
||||
$rule = $this->__generateRule($item['Attribute'], $ruleFormat, $valueField, $whitelist);
|
||||
if (!empty($rule)) {
|
||||
if (!in_array($rule, $intel)) {
|
||||
$intel[] = $rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $intel;
|
||||
}
|
||||
|
||||
private function __generateRule($attribute, $ruleFormat, $valueField, $whitelist) {
|
||||
if (isset($this->mapping[$attribute['type']])) {
|
||||
$brotype = $this->mapping[$attribute['type']]['brotype'];
|
||||
$overruled = $this->checkWhitelist($attribute['value'], $whitelist);
|
||||
if (isset($this->mapping[$attribute['type']]['alternate'])) {
|
||||
if (preg_match($this->mapping[$attribute['type']]['alternate'][0], $attribute['value'])) {
|
||||
$brotype = $this->mapping[$attribute['type']]['alternate'][1];
|
||||
}
|
||||
}
|
||||
if ($valueField == 2 && isset($this->mapping[$attribute['type']]['composite'])) {
|
||||
$brotype = $this->mapping[$attribute['type']]['composite'];
|
||||
}
|
||||
$attribute['value'] = $this->replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
|
||||
if (isset($this->mapping[$attribute['type']]['replace'])) {
|
||||
$attribute['value'] = preg_replace(
|
||||
$this->mapping[$attribute['type']]['replace'][0],
|
||||
$this->mapping[$attribute['type']]['replace'][1],
|
||||
$attribute['value']
|
||||
);
|
||||
}
|
||||
return sprintf($ruleFormat,
|
||||
($overruled) ? '#OVERRULED BY WHITELIST# ' :
|
||||
$attribute['value'], // value - for composite values only the relevant element is taken
|
||||
'Intel:' . $brotype, // type
|
||||
'T', // meta.do_notice
|
||||
'-' // meta.if_in
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces characters that are not allowed in a signature.
|
||||
* example: " is converted to |22|
|
||||
* @param unknown_type $value
|
||||
*/
|
||||
public static function replaceIllegalChars($value) {
|
||||
$replace_pairs = array(
|
||||
'|' => '|7c|', // Needs to stay on top !
|
||||
'"' => '|22|',
|
||||
';' => '|3b|',
|
||||
':' => '|3a|',
|
||||
'\\' => '|5c|',
|
||||
'0x' => '|30 78|'
|
||||
);
|
||||
return strtr($value, $replace_pairs);
|
||||
}
|
||||
|
||||
public function checkWhitelist($value, $whitelist) {
|
||||
foreach ($whitelist as $wlitem) {
|
||||
if (preg_match($wlitem, $value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getMispTypes($type) {
|
||||
$mispTypes = array();
|
||||
if (isset($this->mispTypes[$type])) {
|
||||
$mispTypes = $this->mispTypes[$type];
|
||||
}
|
||||
return $mispTypes;
|
||||
}
|
||||
}
|
|
@ -522,7 +522,6 @@ class Attribute extends AppModel {
|
|||
$value = $fields['value'];
|
||||
$eventId = $this->data['Attribute']['event_id'];
|
||||
$type = $this->data['Attribute']['type'];
|
||||
$toIds = $this->data['Attribute']['to_ids'];
|
||||
$category = $this->data['Attribute']['category'];
|
||||
|
||||
// check if the attribute already exists in the same event
|
||||
|
@ -1411,6 +1410,103 @@ class Attribute extends AppModel {
|
|||
return $values;
|
||||
}
|
||||
|
||||
function bro($user, $type, $tags = false, $eventId = false, $from = false, $to = false, $last = false) {
|
||||
//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) {
|
||||
$conditions['AND'][] = array('Event.id' => $eventId);
|
||||
}
|
||||
else 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;
|
||||
}
|
||||
App::uses('BroExport', 'Export');
|
||||
$export = new BroExport();
|
||||
$this->Whitelist = ClassRegistry::init('Whitelist');
|
||||
$this->whitelist = $this->Whitelist->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);
|
||||
$intel = array($export->header);
|
||||
foreach($mispTypes as $mispType) {
|
||||
$conditions['AND']['Attribute.type'] = $mispType[0];
|
||||
$intel = $this->__bro($intel, $user, $conditions, $mispType[1], $export, $this->whitelist, $instanceString);
|
||||
}
|
||||
return $intel;
|
||||
}
|
||||
|
||||
private function __bro($intel, $user, $conditions, $valueField, $export, $whitelist, $instanceString) {
|
||||
$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.value' . $valueField . " as value"),
|
||||
'contain' => array('Event' => array('fields' => array('Event.id', 'Event.threat_level_id', 'Event.orgc_id', 'Event.uuid'))),
|
||||
'group' => array('Attribute.type', 'Attribute.value' . $valueField), // fields to GROUP BY
|
||||
)
|
||||
);
|
||||
$orgs = $this->Event->Orgc->find('list', array(
|
||||
'fields' => array('Orgc.id', 'Orgc.name')
|
||||
));
|
||||
return $export->export($attributes, $orgs, $valueField, $intel, $whitelist, $instanceString);
|
||||
}
|
||||
|
||||
public function brozip($user, $tags, $eventId, $allowNonIDS, $from, $to, $last, $jobId = false) {
|
||||
App::uses('BroExport', 'Export');
|
||||
$export = new BroExport();
|
||||
$types = array_keys($export->mispTypes);
|
||||
$typeCount = count($types);
|
||||
if ($jobId) {
|
||||
$this->Job = ClassRegistry::init('Job');
|
||||
$this->Job->id = $jobId;
|
||||
if (!$this->Job->exists()) {
|
||||
$jobId = false;
|
||||
}
|
||||
}
|
||||
$dir = new Folder(APP . 'tmp/files/' . $this->Event->generateRandomFileName(), true, 0750);
|
||||
$tmpZipname = DS . "bro_export_tmp.zip";
|
||||
$zip = new File($dir->pwd() . $tmpZipname);
|
||||
foreach ($types as $k => $type) {
|
||||
$final = $this->bro($user, $type, $tags, $eventId, $allowNonIDS, $from, $to, $last);
|
||||
$filename = $type . '.intel';
|
||||
$file = new File($dir->pwd() . DS . $filename);
|
||||
$file->write(implode(PHP_EOL, $final));
|
||||
$file->close();
|
||||
$execRetval = '';
|
||||
$execOutput = array();
|
||||
exec('zip -gj ' . $zip->path . ' ' . $dir->pwd() . '/' . $filename, $execOutput, $execRetval);
|
||||
if ($execRetval != 0) { // not EXIT_SUCCESS
|
||||
throw new Exception('An error has occured while attempting to zip the intel files.');
|
||||
}
|
||||
$file->delete(); // delete the original non-zipped-file
|
||||
if ($jobId) {
|
||||
$this->Job->saveField('progress', $k / $typeCount * 100);
|
||||
}
|
||||
}
|
||||
$zip->close();
|
||||
return array($dir->pwd(), $tmpZipname);
|
||||
}
|
||||
|
||||
public function generateCorrelation($jobId = false, $startPercentage = 0) {
|
||||
$this->Correlation = ClassRegistry::init('Correlation');
|
||||
$this->Correlation->deleteAll(array('id !=' => 0), false);
|
||||
|
@ -1696,12 +1792,12 @@ class Attribute extends AppModel {
|
|||
'recursive' => -1,
|
||||
'contain' => array(
|
||||
'Event' => array(
|
||||
'fields' => array('id', 'info', 'org_id'),
|
||||
'fields' => array('id', 'info', 'org_id', 'orgc_id'),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (isset($options['contain'])) $params['contain'] = array_merge_recursive($params['contain'], $options['contain']);
|
||||
else $option['contain']['Event']['fields'] = array('id', 'info', 'org_id');
|
||||
else $option['contain']['Event']['fields'] = array('id', 'info', 'org_id', 'orgc_id');
|
||||
if (isset($options['fields'])) $params['fields'] = $options['fields'];
|
||||
if (isset($options['conditions'])) $params['conditions']['AND'][] = $options['conditions'];
|
||||
if (isset($options['order'])) $params['order'] = $options['order'];
|
||||
|
|
|
@ -97,6 +97,13 @@ class Event extends AppModel {
|
|||
'canHaveAttachments' => false,
|
||||
'description' => 'Click this to download all network related attributes that you have access to under the Snort rule format. Only published events and attributes marked as IDS Signature are exported. Administration is able to maintain a whitelist containing host, domain name and IP numbers to exclude from the NIDS export.',
|
||||
),
|
||||
'bro' => array(
|
||||
'extension' => '.intel.zip',
|
||||
'type' => 'Bro',
|
||||
'requiresPublished' => 1,
|
||||
'canHaveAttachments' => false,
|
||||
'description' => 'Click this to download all network related attributes that you have access to under the Bro rule format. Only published events and attributes marked as IDS Signature are exported. Administration is able to maintain a whitelist containing host, domain name and IP numbers to exclude from the NIDS export.',
|
||||
),
|
||||
'stix' => array(
|
||||
'extension' => '.xml',
|
||||
'type' => 'STIX',
|
||||
|
|
|
@ -19,18 +19,14 @@ class EventDelegation extends AppModel {
|
|||
);
|
||||
|
||||
public $belongsTo = array(
|
||||
'Event' => array(
|
||||
'className' => 'Event',
|
||||
),
|
||||
'Event',
|
||||
'Org' => array(
|
||||
'className' => 'Organisation',
|
||||
),
|
||||
'RequesterOrg' => array(
|
||||
'className' => 'Organisation'
|
||||
),
|
||||
'SharingGroup' => array(
|
||||
'className' => 'SharingGroup'
|
||||
)
|
||||
'SharingGroup'
|
||||
);
|
||||
|
||||
public function attachTagToEvent($event_id, $tag_id) {
|
||||
|
|
|
@ -19,12 +19,8 @@ class EventTag extends AppModel {
|
|||
);
|
||||
|
||||
public $belongsTo = array(
|
||||
'Event' => array(
|
||||
'className' => 'Event',
|
||||
),
|
||||
'Tag' => array(
|
||||
'className' => 'Tag',
|
||||
),
|
||||
'Event',
|
||||
'Tag'
|
||||
);
|
||||
|
||||
// take an array of tag names to be included and an array with tagnames to be excluded and find all event IDs that fit the criteria
|
||||
|
|
|
@ -50,6 +50,11 @@ class Job extends AppModel {
|
|||
$type = 'nids';
|
||||
$extra2 = isset($user['nids_sid']) ? $user['nids_sid'] : 0;
|
||||
}
|
||||
if ($type === 'bro') {
|
||||
$extra = $type;
|
||||
$type = 'bro';
|
||||
$extra2 = isset($user['nids_sid']) ? $user['nids_sid'] : 0;
|
||||
}
|
||||
if ($type === 'rpz') $extra = $type;
|
||||
$this->save($data);
|
||||
$id = $this->id;
|
||||
|
|
|
@ -18,9 +18,5 @@ class News extends AppModel {
|
|||
)
|
||||
);
|
||||
|
||||
public $belongsTo = array(
|
||||
'User' => array(
|
||||
'className' => 'User',
|
||||
)
|
||||
);
|
||||
public $belongsTo = 'User';
|
||||
}
|
||||
|
|
|
@ -2448,6 +2448,7 @@ class Server extends AppModel {
|
|||
APP . 'tmp' . DS . 'xml' => 0,
|
||||
APP . 'tmp' . DS . 'files' => 0,
|
||||
APP . 'tmp' . DS . 'logs' => 0,
|
||||
APP . 'tmp' . DS . 'bro' => 0,
|
||||
);
|
||||
foreach ($writeableDirs as $path => &$error) {
|
||||
$dir = new Folder($path);
|
||||
|
|
|
@ -19,12 +19,8 @@ class ServerTag extends AppModel {
|
|||
);
|
||||
|
||||
public $belongsTo = array(
|
||||
'Server' => array(
|
||||
'className' => 'Server',
|
||||
),
|
||||
'Tag' => array(
|
||||
'className' => 'Tag',
|
||||
),
|
||||
'Server',
|
||||
'Tag'
|
||||
);
|
||||
|
||||
public function attachTagToServer($server_id, $tag_id) {
|
||||
|
|
|
@ -19,12 +19,8 @@ class Sighting extends AppModel {
|
|||
);
|
||||
|
||||
public $belongsTo = array(
|
||||
'Attribute' => array(
|
||||
'className' => 'Attribute',
|
||||
),
|
||||
'Event' => array(
|
||||
'className' => 'Event',
|
||||
),
|
||||
'Attribute',
|
||||
'Event',
|
||||
'Organisation' => array(
|
||||
'className' => 'Organisation',
|
||||
'foreignKey' => 'org_id'
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
foreach ($attributes as $attribute) {
|
||||
echo $attribute;
|
||||
echo PHP_EOL;
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
<?php echo $this->Form->create('Attribute');?>
|
||||
<fieldset>
|
||||
<legend>Search Attribute</legend>
|
||||
You can search for attributes based on contained expression within the value, event ID, submiting organisation, category and type. <br />For the value, event ID and organisation, you can enter several search terms by entering each term as a new line. To exclude things from a result, use the NOT operator (!) infront of the term.<br/><br />
|
||||
You can search for attributes based on contained expression within the value, event ID, submitting organisation, category and type. <br />For the value, event ID and organisation, you can enter several search terms by entering each term as a new line. To exclude things from a result, use the NOT operator (!) in front of the term.<br/><br />
|
||||
<?php
|
||||
echo $this->Form->input('keyword', array('type' => 'textarea', 'label' => 'Containing the following expressions', 'div' => 'clear', 'class' => 'input-xxlarge'));
|
||||
echo $this->Form->input('keyword2', array('type' => 'textarea', 'label' => 'Being attributes of the following event IDs or event UUIDs', 'div' => 'clear', 'class' => 'input-xxlarge'));
|
||||
|
@ -43,12 +43,12 @@ echo $this->Form->end();
|
|||
</div>
|
||||
<script type="text/javascript">
|
||||
//
|
||||
//Generate Category / Type filtering array
|
||||
// Generate Category / Type filtering array
|
||||
//
|
||||
var category_type_mapping = new Array();
|
||||
|
||||
<?php
|
||||
// all types for Categorie ALL
|
||||
// all types for Category ALL
|
||||
echo "category_type_mapping['ALL'] = {";
|
||||
$first = true;
|
||||
foreach ($typeDefinitions as $type => $def) {
|
||||
|
@ -58,7 +58,7 @@ foreach ($typeDefinitions as $type => $def) {
|
|||
}
|
||||
echo "}; \n";
|
||||
|
||||
//all types for empty Categorie
|
||||
// all types for empty Category
|
||||
echo "category_type_mapping[''] = {";
|
||||
$first = true;
|
||||
foreach ($typeDefinitions as $type => $def) {
|
||||
|
@ -68,7 +68,7 @@ foreach ($typeDefinitions as $type => $def) {
|
|||
}
|
||||
echo "}; \n";
|
||||
|
||||
// Types per Categorie
|
||||
// Types per Category
|
||||
foreach ($categoryDefinitions as $category => $def) {
|
||||
echo "category_type_mapping['" . addslashes($category) . "'] = {";
|
||||
$first = true;
|
||||
|
@ -82,7 +82,7 @@ foreach ($categoryDefinitions as $category => $def) {
|
|||
?>
|
||||
|
||||
//
|
||||
//Generate Type / Category filtering array
|
||||
// Generate Type / Category filtering array
|
||||
//
|
||||
var type_category_mapping = new Array();
|
||||
|
||||
|
@ -182,7 +182,7 @@ $(document).ready(function() {
|
|||
});
|
||||
|
||||
// workaround for browsers like IE and Chrome that do now have an onmouseover on the 'options' of a select.
|
||||
// disadvangate is that user needs to click on the item to see the tooltip.
|
||||
// disadvantage is that user needs to click on the item to see the tooltip.
|
||||
// no solutions exist, except to generate the select completely using html.
|
||||
$("#AttributeType, #AttributeCategory").on('change', function(e) {
|
||||
var $e = $(e.target);
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
<?php
|
||||
echo $this->element('eventattributerow', array('object' => $object));
|
|
@ -3,7 +3,7 @@
|
|||
<table>
|
||||
<tr>
|
||||
<td style="padding-right:0px;">
|
||||
<span class="<?php echo ($editable == 'yes' ? 'tagFirstHalf' : 'tagComplete'); ?>" style="background-color:<?php echo h($tag['Tag']['colour']);?>;color:<?php echo $this->TextColour->getTextColour($tag['Tag']['colour']);?>"><?php echo h($tag['Tag']['name']); ?></a>
|
||||
<span class="<?php echo ($editable == 'yes' ? 'tagFirstHalf' : 'tagComplete'); ?>" style="background-color:<?php echo h($tag['Tag']['colour']);?>;color:<?php echo $this->TextColour->getTextColour($tag['Tag']['colour']);?>"><?php echo h($tag['Tag']['name']); ?></span>
|
||||
</td>
|
||||
<?php if ($editable == 'yes'): ?>
|
||||
<td style="padding-left:0px;padding-right:5px;">
|
||||
|
|
|
@ -204,7 +204,61 @@ Use semicolons instead (the search will automatically search for colons instead)
|
|||
echo $baseurl.'/attributes/text/download/all/tag1&&tag2&&!tag3';
|
||||
?>
|
||||
</pre>
|
||||
<h3>Bro IDS export</h3>
|
||||
<p>An export of all attributes of a specific bro type to a formatted plain text file. By default only published and IDS flagged attributes are exported.</p>
|
||||
<p>You can configure your tools to automatically download a file one of the Bro types.</p>
|
||||
<pre>
|
||||
<?php
|
||||
foreach (array_keys($broTypes) as $broType) {
|
||||
echo $baseurl.'/attributes/bro/download/'.$broType . "\n";
|
||||
}
|
||||
?>
|
||||
</pre>
|
||||
<p>To restrict the results by tags, use the usual syntax. Please be aware the colons (:) cannot be used in the tag search. Use semicolons instead (the search will automatically search for colons instead). To get ip values from events tagged tag1 but not tag2 use:</p>
|
||||
<pre>
|
||||
<?php
|
||||
echo $baseurl.'/attributes/bro/download/ip/tag1&&!tag2';
|
||||
?>
|
||||
</pre>
|
||||
|
||||
<p>It is possible to restrict the bro exports on based on a set of filters. POST a JSON object or an XML at the Bro API to filter the results.</p>
|
||||
<pre>
|
||||
<?php
|
||||
echo $baseurl.'/attributes/bro/download';
|
||||
?>
|
||||
</pre>
|
||||
<p>JSON:</p>
|
||||
<pre>Headers
|
||||
Authorization: [your API key]
|
||||
Accept: application/json
|
||||
Content-type: application/json
|
||||
</pre>
|
||||
<code>{"request": {"type":"ip", "eventid":["!51","!62"],"withAttachment":false,"tags":["APT1","!OSINT"],"from":false,"to":"2015-02-15"}}</code><br /><br />
|
||||
<p>XML:</p>
|
||||
<pre>Headers
|
||||
Authorization: [your API key]
|
||||
Accept: application/json
|
||||
Content-type: application/json
|
||||
</pre>
|
||||
<code><request><type>ip</type><eventid>!51</eventid><eventid>!62</eventid><withAttachment>false</withAttachment><tags>APT1</tags><tags>!OSINT</tags><from>false</from><to>2015-02-15</to></request></code><br /><br />
|
||||
<p>Alternatively, it is also possible to pass the filters via the parameters in the URL, though it is highly advised to use POST requests with JSON objects instead. The format is as described below:</p>
|
||||
<pre>
|
||||
<?php
|
||||
echo $baseurl.'/attributes/bro/download/[type]/[tags]/[event_id]/[allowNonIDS]/[from]/[to]/[last]';
|
||||
?>
|
||||
</pre>
|
||||
<b>type</b>: The Bro type, any valid Bro type is accepted. The mapping between Bro and MISP types is as follows:<br />
|
||||
<pre>
|
||||
<?php
|
||||
foreach ($broTypes as $key => $value) {
|
||||
echo '<b>' . h($key) . '</b>: ' . h($value) . PHP_EOL;
|
||||
}
|
||||
?>
|
||||
</pre>
|
||||
<p>
|
||||
<b>tags</b>: To include a tag in the results just write its names into this parameter. To exclude a tag prepend it with a '!'.
|
||||
You can also chain several tag commands together with the '&&' operator. Please be aware the colons (:) cannot be used in the tag search.
|
||||
Use semicolons instead (the search will automatically search for colons instead).<br />
|
||||
<b>event_id</b>: Restrict the results to the given event IDs. <br />
|
||||
<b>allowNonIDS</b>: Allow attributes to be exported that are not marked as "to_ids".<br />
|
||||
<b>from</b>: Events with the date set to a date after the one specified in the from field (format: 2015-02-15). This filter will use the date of the event.<br />
|
||||
|
|
|
@ -38,7 +38,18 @@
|
|||
domain name and IP numbers to exclude from the NIDS export.
|
||||
</div>
|
||||
</div>
|
||||
<div class="row bottom-buffer">
|
||||
<div class="row bottom-buffer">
|
||||
<div class="span3">
|
||||
<?php echo $this->Html->link('Download Bro signatures', array('controller' => 'attributes', 'action' => 'bro', 'download'), array('class' => 'btn btn-block full-width')); ?>
|
||||
</div>
|
||||
<div class="span9">Click these to download all network related attributes that you
|
||||
have access to under the Bro rule format. Only <em>published</em>
|
||||
events and attributes marked as <em>IDS Signature</em> are exported.
|
||||
Administration is able to maintain a whitelist containing host,
|
||||
domain name and IP numbers to exclude from the NIDS export.
|
||||
</div>
|
||||
</div>
|
||||
<div class="row bottom-buffer">
|
||||
<div class="span3">
|
||||
<?php echo $this->Html->link('Download RPZ Zone File', array('controller' => 'attributes', 'action' => 'rpz', 'download'), array('class' => 'btn btn-block full-width')); ?>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<div class="succes index">
|
||||
<h2>Succes</h2><?php
|
||||
if (0 == count($succes)):?>
|
||||
<p>No Successes.</p><?php
|
||||
else:?>
|
||||
<p>Succes, all done.</p><?php
|
||||
endif;?>
|
||||
</div>
|
|
@ -30,7 +30,6 @@
|
|||
echo $this->Html->script('jquery'); // Include jQuery library
|
||||
?>
|
||||
|
||||
<!--?php echo $scripts_for_layout; ?-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="popover_form" class="ajax_popover_form"></div>
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
</title>
|
||||
<?php
|
||||
echo $this->Html->meta('icon');
|
||||
// echo $this->Html->css('cake.generic');
|
||||
echo $this->Html->css('roboto');
|
||||
echo $this->Html->css('bootstrap'); // see http://twitter.github.io/bootstrap/base-css.html
|
||||
echo $this->Html->css('bootstrap-datepicker');
|
||||
|
@ -19,9 +18,6 @@
|
|||
echo $this->Html->css('main');
|
||||
echo $this->Html->css('print', 'stylesheet', array('media' => 'print'));
|
||||
|
||||
// FIXME chri: re-add print stylesheet
|
||||
//echo $this->Html->css(array('print'), 'stylesheet', array('media' => 'print'));
|
||||
|
||||
echo $this->fetch('meta');
|
||||
echo $this->fetch('css');
|
||||
echo $this->fetch('script');
|
||||
|
@ -29,7 +25,6 @@
|
|||
echo $this->Html->script('jquery'); // Include jQuery library
|
||||
?>
|
||||
|
||||
<!--?php echo $scripts_for_layout; ?-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="gray_out" class="gray_out"></div>
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<div class="succes index">
|
||||
<h2>Succes</h2><?php
|
||||
if (0 == count($succes)):?>
|
||||
<p>No Successes.</p><?php
|
||||
else:?>
|
||||
<p>Succes, all done.</p><?php
|
||||
endif;?>
|
||||
</div>
|
|
@ -400,29 +400,6 @@ function submitForm(type, id, field, context) {
|
|||
return false;
|
||||
};
|
||||
|
||||
function submitTagForm(id) {
|
||||
$.ajax({
|
||||
data: $('#EventTag').closest("form").serialize(),
|
||||
beforeSend: function (XMLHttpRequest) {
|
||||
$(".loading").show();
|
||||
},
|
||||
success:function (data, textStatus) {
|
||||
loadEventTags(id);
|
||||
handleGenericAjaxResponse(data);
|
||||
},
|
||||
error:function() {
|
||||
showMessage('fail', 'Could not add tag.');
|
||||
loadEventTags(id);
|
||||
},
|
||||
complete:function() {
|
||||
$(".loading").hide();
|
||||
},
|
||||
type:"post",
|
||||
url:"/events/addTag/" + id
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
function quickSubmitTagForm(event_id, tag_id) {
|
||||
$('#EventTag').val(tag_id);
|
||||
$.ajax({
|
||||
|
|
Loading…
Reference in New Issue