mirror of https://github.com/MISP/MISP
- Performance improvements when exporting a large number of attributes into Bro format.
- Fixed file header formatting for the export to Bro format (tabs used consistently). - Computing the time needed for generating the export to Bro format when done using a background job. - When generating the Bro export from the UI all the attributes are generated in one single text file similar to the CSV export instead of a zip file with different files inside. - Changed the file extension of Bro export files from ".intel" to ".txt". - Removed the allowNonIDS option from the Bro export as it doesn’t make sense to have it (Bro is an IDS). - Fixed some of the API endpoints which were not accepted (ACL issues). - Added support for a list of events that should be / should not be included in the export. - Added a new "meta.desc" column (added in Bro 2.5, see https://www.bro.org/sphinx/frameworks/intel.html) containing the description of the event and of the attribute. - Sanitized the exported data for Bro. - Fixed a number of value substitutions which were imported from Snort/Suricata and which were not working for Bro. Did instead substitutions needed for Bro.pull/1726/head
parent
59509699e4
commit
4c022beafc
|
@ -329,27 +329,36 @@ class EventShell extends AppShell
|
|||
|
||||
public function cachebro()
|
||||
{
|
||||
$broHeader = "#fields indicator\tindicator_type\tmeta.source\tmeta.url\tmeta.do_notice\tmeta.if_in\n";
|
||||
$timeStart = time();
|
||||
$broHeader = "#fields\tindicator\tindicator_type\tmeta.source\tmeta.desc\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
|
||||
App::uses('BroExport', 'Export');
|
||||
$export = new BroExport();
|
||||
$types = array_keys($export->mispTypes);
|
||||
$typeCount = count($types);
|
||||
$dir = new Folder(APP . DS . '/tmp/cached_exports/' . $format, true, 0750);
|
||||
$dir = new Folder(APP . DS . '/tmp/cached_exports/bro', true, 0750);
|
||||
if ($user['Role']['perm_site_admin']) {
|
||||
$zipname = DS . 'misp.bro.ADMIN.intel.zip';
|
||||
$file = new File($dir->pwd() . DS . 'misp.bro.ADMIN.txt');
|
||||
} else {
|
||||
$zipname = DS . 'misp.bro.' . $user['Organisation']['name'] . '.intel.zip';
|
||||
$file = new File($dir->pwd() . DS . 'misp.bro.' . $user['Organisation']['name'] . '.txt');
|
||||
}
|
||||
$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();
|
||||
|
||||
foreach ($types as $k => $type) {
|
||||
$final = $this->Attribute->bro($user, $type);
|
||||
foreach ($final as $attribute) {
|
||||
$file->append($attribute . PHP_EOL);
|
||||
}
|
||||
$this->Job->saveField('progress', $k / $typeCount * 100);
|
||||
}
|
||||
$file->close();
|
||||
$timeDelta = (time()-$timeStart);
|
||||
$this->Job->saveField('progress', 100);
|
||||
$this->Job->saveField('message', 'Job done.');
|
||||
$this->Job->saveField('message', 'Job done. (in '.$timeDelta.'s)');
|
||||
$this->Job->saveField('date_modified', date("y-m-d H:i:s"));
|
||||
}
|
||||
|
||||
public function alertemail() {
|
||||
|
|
|
@ -54,7 +54,7 @@ class AppController extends Controller {
|
|||
// This is used to allow authentication via headers for methods not covered by _isRest() - as that only checks for JSON and XML formats
|
||||
public $automationArray = array(
|
||||
'events' => array('csv', 'nids', 'hids', 'xml', 'restSearch', 'stix', 'updateGraph', 'downloadOpenIOCEvent'),
|
||||
'attributes' => array('text', 'downloadAttachment', 'returnAttributes', 'restSearch', 'rpz'),
|
||||
'attributes' => array('text', 'downloadAttachment', 'returnAttributes', 'restSearch', 'rpz', 'bro'),
|
||||
);
|
||||
|
||||
public function __construct($id = false, $table = null, $ds = null) {
|
||||
|
|
|
@ -23,6 +23,7 @@ class AttributesController extends AppController {
|
|||
$this->Auth->allow('downloadAttachment');
|
||||
$this->Auth->allow('text');
|
||||
$this->Auth->allow('rpz');
|
||||
$this->Auth->allow('bro');
|
||||
|
||||
// permit reuse of CSRF tokens on the search page.
|
||||
if ('search' == $this->request->params['action']) {
|
||||
|
@ -459,7 +460,7 @@ class AttributesController extends AppController {
|
|||
$info['distribution'][$key] = array('key' => $value, 'desc' => $this->Attribute->distributionDescriptions[$key]['formdesc']);
|
||||
}
|
||||
$this->set('info', $info);
|
||||
|
||||
|
||||
$this->loadModel('SharingGroup');
|
||||
$sgs = $this->SharingGroup->fetchAllAuthorised($this->Auth->user(), 'name', 1);
|
||||
$this->set('sharingGroups', $sgs);
|
||||
|
@ -671,7 +672,7 @@ class AttributesController extends AppController {
|
|||
}
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
if (!isset($this->request->data['Attribute'])) {
|
||||
$this->request->data['Attribute'] = $this->request->data;
|
||||
$this->request->data['Attribute'] = $this->request->data;
|
||||
}
|
||||
$existingAttribute = $this->Attribute->findByUuid($this->Attribute->data['Attribute']['uuid']);
|
||||
// check if the attribute has a timestamp already set (from a previous instance that is trying to edit via synchronisation)
|
||||
|
@ -1624,7 +1625,7 @@ class AttributesController extends AppController {
|
|||
foreach ($found_orgs as $o) $subcondition['OR'][] = array('Event.orgc_id' => $o['Org']['id']);
|
||||
} else if ($parameters[$k] === 'eventid') {
|
||||
if (!empty($v)) $subcondition['OR'][] = array('Attribute.event_id' => $v);
|
||||
} else if ($parameters[$k] === 'uuid') {
|
||||
} else if ($parameters[$k] === 'uuid') {
|
||||
$subcondition['OR'][] = array('Attribute.uuid' => $v);
|
||||
$subcondition['OR'][] = array('Event.uuid' => $v);
|
||||
} else {
|
||||
|
@ -1666,7 +1667,7 @@ class AttributesController extends AppController {
|
|||
}
|
||||
if ($last) $conditions['AND'][] = array('Event.publish_timestamp >=' => $last);
|
||||
if ($published) $conditions['AND'][] = array('Event.published' => $published);
|
||||
|
||||
|
||||
// change the fields here for the attribute export!!!! Don't forget to check for the permissions, since you are not going through fetchevent. Maybe create fetchattribute?
|
||||
$params = array(
|
||||
'conditions' => $conditions,
|
||||
|
@ -1919,7 +1920,7 @@ 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) {
|
||||
public function bro($key='download', $type='all', $tags=false, $eventId=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);
|
||||
|
@ -1929,49 +1930,39 @@ class AttributesController extends AppController {
|
|||
if (!empty($data) && !isset($data['request'])) {
|
||||
$data = array('request' => $data);
|
||||
}
|
||||
$paramArray = array('type', 'tags', 'eventId', 'allowNonIDS', 'from', 'to', 'last');
|
||||
$paramArray = array('type', 'tags', 'eventId', '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');
|
||||
$simpleFalse = array('type', 'tags', 'eventId', '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.');
|
||||
}
|
||||
if ($type === 'null' || $type === '0' || $type === 'false') $type = 'all';
|
||||
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.');
|
||||
}
|
||||
$filename = 'misp.' . $type . '.intel';
|
||||
if ($eventId) {
|
||||
$filename = 'misp.' . $type . '.event_' . $eventId . '.intel';
|
||||
} else {
|
||||
if (!$this->Auth->user('id')) {
|
||||
throw new UnauthorizedException('You have to be logged in to do that.');
|
||||
}
|
||||
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;
|
||||
}
|
||||
$filename = 'misp.' . $type . '.txt';
|
||||
if ($eventId) {
|
||||
$filename = 'misp.' . $type . '.event_' . $eventId . '.txt';
|
||||
}
|
||||
$responseFile = implode(PHP_EOL, $this->Attribute->bro($this->Auth->user(), $type, $tags, $eventId, $from, $to, $last)) . PHP_EOL;
|
||||
$this->response->body($responseFile);
|
||||
$this->response->type('txt');
|
||||
$this->response->download($filename);
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
public function reportValidationIssuesAttributes($eventId = false) {
|
||||
|
@ -2350,7 +2341,7 @@ class AttributesController extends AppController {
|
|||
$this->Session->setFlash('Removed ' . count($orphans) . ' attribute(s).');
|
||||
$this->redirect(Router::url($this->referer(), true));
|
||||
}
|
||||
|
||||
|
||||
public function checkOrphanedAttributes() {
|
||||
if (!$this->_isSiteAdmin()) throw new MethodNotAllowedException('You are not authorised to do that.');
|
||||
$this->loadModel('Attribute');
|
||||
|
@ -2457,7 +2448,7 @@ class AttributesController extends AppController {
|
|||
public function describeTypes() {
|
||||
$result = array();
|
||||
foreach ($this->Attribute->typeDefinitions as $key => $value) {
|
||||
$result['sane_defaults'][$key] = array('default_category' => $value['default_category'], 'to_ids' => $value['to_ids']);
|
||||
$result['sane_defaults'][$key] = array('default_category' => $value['default_category'], 'to_ids' => $value['to_ids']);
|
||||
}
|
||||
$result['types'] = array_keys($this->Attribute->typeDefinitions);
|
||||
$result['categories'] = array_keys($this->Attribute->categoryDefinitions);
|
||||
|
|
|
@ -56,6 +56,7 @@ class ACLComponent extends Component {
|
|||
'restSearch' => array('*'),
|
||||
'returnAttributes' => array('*'),
|
||||
'rpz' => array('*'),
|
||||
'bro' => array('*'),
|
||||
'search' => array('*'),
|
||||
'searchAlternate' => array('*'),
|
||||
'text' => array('*'),
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
class BroExport {
|
||||
|
||||
|
||||
public $rules = array();
|
||||
|
||||
public $header = "#fields indicator\tindicator_type\tmeta.source\tmeta.url\tmeta.do_notice\tmeta.if_in";
|
||||
|
||||
|
||||
public $header = "#fields\tindicator\tindicator_type\tmeta.source\tmeta.desc\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
|
||||
|
@ -32,7 +32,7 @@ class BroExport {
|
|||
'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(
|
||||
|
@ -81,7 +81,8 @@ class BroExport {
|
|||
|
||||
private $whitelist = null;
|
||||
|
||||
public function export($items, $orgs, $valueField, $intel, $whitelist, $instanceString) {
|
||||
public function export($items, $orgs, $valueField, $whitelist, $instanceString) {
|
||||
$intel = array();
|
||||
//For bro format organisation
|
||||
$orgsName = array();
|
||||
// generate the rules
|
||||
|
@ -92,65 +93,62 @@ class BroExport {
|
|||
$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";
|
||||
$ruleFormat = "%s\t%s\t" . $orgName . "\t" . $this->replaceIllegalChars($item['Event']['info']) . ". %s" . "\t" . $ruleFormatReference . "\t%s\t%s";
|
||||
$rule = $this->__generateRule($item['Attribute'], $ruleFormat, $valueField, $whitelist);
|
||||
if (!empty($rule)) {
|
||||
if (!in_array($rule, $intel)) {
|
||||
$intel[] = $rule;
|
||||
}
|
||||
$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 (! $this->checkWhitelist($attribute['value'], $whitelist)) {
|
||||
$brotype = $this->mapping[$attribute['type']]['brotype'];
|
||||
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
|
||||
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,
|
||||
$attribute['value'], // value - for composite values only the relevant element is taken
|
||||
'Intel::' . $brotype, // type
|
||||
$attribute['comment'],
|
||||
'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|'
|
||||
"\t" => ' ',
|
||||
"\x0B" => ' ',
|
||||
"\r" => ' ',
|
||||
"\r\n" => ' ',
|
||||
"\n" => ' '
|
||||
);
|
||||
return strtr($value, $replace_pairs);
|
||||
return html_entity_decode(filter_var(strtr($value, $replace_pairs), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH));
|
||||
}
|
||||
|
||||
|
||||
public function checkWhitelist($value, $whitelist) {
|
||||
foreach ($whitelist as $wlitem) {
|
||||
if (preg_match($wlitem, $value)) {
|
||||
|
@ -159,12 +157,12 @@ class BroExport {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function getMispTypes($type) {
|
||||
$mispTypes = array();
|
||||
if (isset($this->mispTypes[$type])) {
|
||||
$mispTypes = $this->mispTypes[$type];
|
||||
$mispTypes = $this->mispTypes[$type];
|
||||
}
|
||||
return $mispTypes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1413,57 +1413,77 @@ 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;
|
||||
}
|
||||
public function bro($user, $type, $tags = false, $eventId = false, $from = false, $to = false, $last = false) {
|
||||
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';
|
||||
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->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);
|
||||
foreach($mispTypes as $mispType) {
|
||||
$conditions['AND']['Attribute.type'] = $mispType[0];
|
||||
$intel = array_merge($intel, $this->__bro($user, $conditions, $mispType[1], $export, $this->whitelist, $instanceString));
|
||||
}
|
||||
}
|
||||
$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);
|
||||
}
|
||||
natsort($intel);
|
||||
$intel = array_unique($intel);
|
||||
array_unshift($intel, $export->header);
|
||||
return $intel;
|
||||
}
|
||||
|
||||
private function __bro($intel, $user, $conditions, $valueField, $export, $whitelist, $instanceString) {
|
||||
private function __bro($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"),
|
||||
'fields' => array('Attribute.id', 'Attribute.event_id', 'Attribute.type', 'Attribute.comment', '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
|
||||
)
|
||||
|
@ -1471,43 +1491,7 @@ class Attribute extends AppModel {
|
|||
$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);
|
||||
return $export->export($attributes, $orgs, $valueField, $whitelist, $instanceString);
|
||||
}
|
||||
|
||||
public function generateCorrelation($jobId = false, $startPercentage = 0) {
|
||||
|
|
|
@ -99,7 +99,7 @@ class Event extends AppModel {
|
|||
'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',
|
||||
'extension' => '.txt',
|
||||
'type' => 'Bro',
|
||||
'requiresPublished' => 1,
|
||||
'canHaveAttachments' => false,
|
||||
|
|
Loading…
Reference in New Issue