Merge branch 'develop' into feature/XML_and_UI

pull/217/head
iglocska 2013-10-24 16:10:58 +02:00
commit 0cb7653d41
15 changed files with 783 additions and 220 deletions

View File

@ -295,6 +295,8 @@ class AppController extends Controller {
$this->loadModel('Role');
$this->Role->recursive = -1;
$role = $this->Role->findById($user['User']['role_id']);
$user['User']['siteAdmin'] = false;
if ($role['Role']['perm_admin'] && $user['User']['org'] == 'ADMIN') $user['User']['siteAdmin'] = true;
if ($role['Role']['perm_auth']) {
return $user;
}

View File

@ -21,6 +21,10 @@ class AttributesController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('restSearch');
$this->Auth->allow('returnAttributes');
$this->Auth->allow('downloadAttachment');
// permit reuse of CSRF tokens on the search page.
if ('search' == $this->request->params['action']) {
@ -246,19 +250,18 @@ class AttributesController extends AppController {
if (!$this->Attribute->exists()) {
throw new NotFoundException(__('Invalid attribute'));
}
$this->Attribute->read();
if (!$this->_isSiteAdmin() &&
$this->Auth->user('org') !=
$this->Attribute->data['Event']['org'] &&
($this->Attribute->data['Event']['distribution'] == 0 ||
$this->Attribute->data['Attribute']['distribution'] == 0
)) {
throw new UnauthorizedException('You do not have the permission to view this event.');
$this->Auth->user('org') !=
$this->Attribute->data['Event']['org'] &&
($this->Attribute->data['Event']['distribution'] == 0 ||
$this->Attribute->data['Attribute']['distribution'] == 0
)) {
throw new UnauthorizedException('You do not have the permission to view this event.');
}
$this->__downloadAttachment($this->Attribute->data['Attribute']);
}
}
private function __downloadAttachment($attribute) {
$path = "files" . DS . $attribute['event_id'] . DS;
$file = $attribute['id'];
@ -1069,4 +1072,172 @@ class AttributesController extends AppController {
$this->set('fails', $this->Attribute->checkComposites());
}
// Use the rest interface to search for attributes. Usage:
// MISP-base-url/attributes/restSearch/[api-key]/[value]/[type]/[category]/[orgc]
// value, type, category, orgc are optional
// the last 4 fields accept the following operators:
// && - you can use && between two search values to put a logical OR between them. for value, 1.1.1.1&&2.2.2.2 would find attributes with the value being either of the two.
// ! - you can negate a search term. For example: google.com&&!mail would search for all attributes with value google.com but not ones that include mail. www.google.com would get returned, mail.google.com wouldn't.
public function restSearch($key, $value=null, $type=null, $category=null, $org=null) {
$user = $this->checkAuthUser($key);
if (!$user) {
throw new UnauthorizedException('This authentication key is not authorized to be used for exports. Contact your administrator.');
}
$this->response->type('xml'); // set the content type
$this->layout = 'xml/default';
$this->header('Content-Disposition: download; filename="misp.search.attribute.results.xml"');
$conditions['AND'] = array();
$subcondition = array();
$this->loadModel('Attribute');
// add the values as specified in the 2nd parameter to the conditions
$values = explode('&&', $value);
$parameters = array('value', 'type', 'category', 'org');
foreach ($parameters as $k => $param) {
if (isset(${$parameters[$k]})) {
$elements = explode('&&', ${$parameters[$k]});
foreach($elements as $v) {
if (substr($v, 0, 1) == '!') {
$subcondition['AND'][] = array('Attribute.' . $parameters[$k] . ' NOT LIKE' => '%'.substr($v, 1).'%');
} else {
$subcondition['OR'][] = array('Attribute.' . $parameters[$k] . ' LIKE' => '%'.$v.'%');
}
}
array_push ($conditions['AND'], $subcondition);
$subcondition = array();
}
}
// If we are looking for an attribute, we want to retrieve some extra data about the event to be able to check for the permissions.
if (!$user['User']['siteAdmin']) {
$temp = array();
$temp['AND'] = array('Event.distribution >' => 0, 'Attribute.distribution >' => 0);
$subcondition['OR'][] = $temp;
$subcondition['OR'][] = array('Event.org' => $user['User']['org']);
array_push($conditions['AND'], $subcondition);
}
// 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,
'fields' => array('Attribute.*', 'Event.org', 'Event.distribution'),
'contain' => 'Event'
);
$results = $this->Attribute->find('all', $params);
$this->loadModel('Whitelist');
$results = $this->Whitelist->removeWhitelistedFromArray($results, false);
if (empty($results)) throw new NotFoundException('No matches.');
$this->set('results', $results);
}
// returns an XML with attributes that belong to an event. The type of attributes to be returned can be restricted by type using the 3rd parameter.
// Similar to the restSearch, this parameter can be chained with '&&' and negations are accepted too. For example filename&&!filename|md5 would return all filenames that don't have an md5
// The usage of returnAttributes is the following: [MISP-url]/attributes/returnAttributes/<API-key>/<type>/<signature flag>
// The signature flag is off by default, enabling it will only return attribugtes that have the to_ids flag set to true.
public function returnAttributes($key, $id, $type = null, $sigOnly = false) {
$user = $this->checkAuthUser($key);
// if the user is authorised to use the api key then user will be populated with the user's account
// in addition we also set a flag indicating whether the user is a site admin or not.
if (!$user) {
throw new UnauthorizedException('This authentication key is not authorized to be used for exports. Contact your administrator.');
}
$this->loadModel('Event');
$this->Event->read(null, $id);
$myEventOrAdmin = false;
if ($user['User']['siteAdmin'] || $this->Event->data['Event']['org'] == $user['User']['org']) {
$myEventOrAdmin = true;
}
if (!$myEventOrAdmin) {
if ($this->Event->data['Event']['distribution'] == 0) {
throw new UnauthorizedException('You don\'t have access to that event.');
}
}
$this->response->type('xml'); // set the content type
$this->layout = 'xml/default';
$this->header('Content-Disposition: download; filename="misp.search.attribute.results.xml"');
// check if user can see the event!
$conditions['AND'] = array();
$include = array();
$exclude = array();
$attributes = array();
// If there is a type set, create the include and exclude arrays from it
if (isset($type)) {
$elements = explode('&&', $type);
foreach($elements as $v) {
if (substr($v, 0, 1) == '!') {
$exclude[] = substr($v, 1);
} else {
$include[] = $v;
}
}
}
// check each attribute
foreach($this->Event->data['Attribute'] as $k => $attribute) {
$contained = false;
// If the include list is empty, then we just then the first check should always set contained to true (basically we chose type = all - exclusions, or simply all)
if (empty($include)) {
$contained = true;
} else {
// If we have elements in $include we should check if the attribute's type should be included
foreach ($include as $inc) {
if (strpos($attribute['type'], $inc) !== false) {
$contained = true;
}
}
}
// If we have either everything included or the attribute passed the include check, we should check if there is a reason to exclude the attribute
// For example, filename may be included, but md5 may be excluded, meaning that filename|md5 should be removed
if ($contained) {
foreach ($exclude as $exc) {
if (strpos($attribute['type'], $exc) !== false) {
$contained = false;
continue 2;
}
}
}
// If we still didn't throw the attribute away, let's check if the user requesting the attributes is of the owning organisation of the event
// and if not, whether the distribution of the attribute allows the user to see it
if ($contained && !$myEventOrAdmin && $attribute['distribution'] == 0) {
$contained = false;
}
// If we have set the sigOnly parameter and the attribute has to_ids set to false, discard it!
if ($contained && $sigOnly === 'true' && !$attribute['to_ids']) {
$contained = false;
}
// If after all of this $contained is still true, let's add the attribute to the array
if ($contained) $attributes[] = $attribute;
}
if (empty($attributes)) throw new NotFoundException('No matches.');
$this->set('results', $attributes);
}
public function downloadAttachment($key, $id) {
$user = $this->checkAuthUser($key);
// if the user is authorised to use the api key then user will be populated with the user's account
// in addition we also set a flag indicating whether the user is a site admin or not.
if (!$user) {
throw new UnauthorizedException('This authentication key is not authorized to be used for exports. Contact your administrator.');
}
$this->Attribute->id = $id;
if(!$this->Attribute->exists()) {
throw new NotFoundException('Invalid attribute or no authorisation to view it.');
}
$this->Attribute->read(null, $id);
if (!$user['User']['siteAdmin'] &&
$user['User']['org'] != $this->Attribute->data['Event']['org'] &&
($this->Attribute->data['Event']['distribution'] == 0 ||
$this->Attribute->data['Attribute']['distribution'] == 0
)) {
throw new NotFoundException('Invalid attribute or no authorisation to view it.');
}
$this->__downloadAttachment($this->Attribute->data['Attribute']);
}
}

View File

@ -6,7 +6,11 @@ class NidsExportComponent extends Component {
public $classtype = 'trojan-activity';
public $format = ""; // suricata (default), snort
public function explain() {
$this->rules[] = '# MISP export of IDS rules - optimized for '.$this->format;
$this->rules[] = '#';
$this->rules[] = '# These NIDS rules contain some variables that need to exist in your configuration.';
$this->rules[] = '# Make sure you have set:';
$this->rules[] = '#';
@ -19,12 +23,15 @@ class NidsExportComponent extends Component {
private $whitelist = null;
public function export($items, $startSid) {
public function export($items, $startSid, $format="suricata") {
$this->format = $format;
$this->Whitelist = ClassRegistry::init('Whitelist');
$this->whitelist = $this->Whitelist->getBlockedValues();
// output a short explanation
$this->explain();
// generate the rules
foreach ($items as &$item) {
switch ($item['Event']['risk']) {
case 'Undefined':
@ -99,6 +106,7 @@ class NidsExportComponent extends Component {
public function ipDstRule($ruleFormat, $attribute, &$sid) {
$overruled = $this->checkWhitelist($attribute['value']);
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'ip', // proto
@ -108,8 +116,8 @@ class NidsExportComponent extends Component {
$attribute['value'], // dst_ip
'any', // dst_port
'Outgoing To IP: ' . $attribute['value'], // msg
'', // rule_content
'', // tag
'', // rule_content
'', // tag
$sid, // sid
1 // rev
);
@ -117,6 +125,7 @@ class NidsExportComponent extends Component {
public function ipSrcRule($ruleFormat, $attribute, &$sid) {
$overruled = $this->checkWhitelist($attribute['value']);
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'ip', // proto
@ -126,8 +135,8 @@ class NidsExportComponent extends Component {
'$HOME_NET', // dst_ip
'any', // dst_port
'Incoming From IP: ' . $attribute['value'], // msg
'', // rule_content
'', // tag
'', // rule_content
'', // tag
$sid, // sid
1 // rev
);
@ -135,13 +144,14 @@ class NidsExportComponent extends Component {
public function emailSrcRule($ruleFormat, $attribute, &$sid) {
$overruled = $this->checkWhitelist($attribute['value']);
$content = 'flow:established,to_server; content:"MAIL FROM|3a|"; nocase; content:"' . $attribute['value'] . '"; nocase;';
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$content = 'flow:established,to_server; content:"MAIL FROM|3a|"; nocase; content:"' . $attribute['value'] . '"; fast_pattern; nocase; content:"|0D 0A 0D 0A|"; within:8192;';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'tcp', // proto
'$EXTERNAL_NET', // src_ip
'any', // src_port
'<>', // direction
'->', // direction
'$SMTP_SERVERS', // dst_ip
'25', // dst_port
'Source Email Address: ' . $attribute['value'], // msg
@ -154,18 +164,19 @@ class NidsExportComponent extends Component {
public function emailDstRule($ruleFormat, $attribute, &$sid) {
$overruled = $this->checkWhitelist($attribute['value']);
$content = 'flow:established,to_server; content:"RCPT TO|3a|"; nocase; content:"' . $attribute['value'] . '"; nocase;';
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$content = 'flow:established,to_server; content:"RCPT TO|3a|"; nocase; content:"' . $attribute['value'] . '"; fast_pattern; nocase; content:"|0D 0A 0D 0A|"; within:8192;';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'tcp', // proto
'$EXTERNAL_NET', // src_ip
'any', // src_port
'<>', // direction
'->', // direction
'$SMTP_SERVERS', // dst_ip
'25', // dst_port
'Destination Email Address: ' . $attribute['value'], // msg
$content, // rule_content
'tag:session,600,seconds;', // tag
'tag:session,600,seconds;', // tag
$sid, // sid
1 // rev
);
@ -174,13 +185,14 @@ class NidsExportComponent extends Component {
public function emailSubjectRule($ruleFormat, $attribute, &$sid) {
// LATER nids - email-subject rule might not match because of line-wrapping
$overruled = $this->checkWhitelist($attribute['value']);
$content = 'flow:established,to_server; content:"Subject|3a|"; nocase; content:"' . $attribute['value'] . '"; nocase;';
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$content = 'flow:established,to_server; content:"Subject|3a|"; nocase; content:"' . $attribute['value'] . '"; fast_pattern; nocase; content:"|0D 0A 0D 0A|"; within:8192;';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'tcp', // proto
'$EXTERNAL_NET', // src_ip
'any', // src_port
'<>', // direction
'->', // direction
'$SMTP_SERVERS', // dst_ip
'25', // dst_port
'Bad Email Subject', // msg
@ -194,13 +206,14 @@ class NidsExportComponent extends Component {
public function emailAttachmentRule($ruleFormat, $attribute, &$sid) {
// LATER nids - email-attachment rule might not match because of line-wrapping
$overruled = $this->checkWhitelist($attribute['value']);
$content = 'flow:established,to_server; content:"Content-Disposition: attachment|3b| filename=|22|"; content:"' . $attribute['value'] . '|22|";';
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$content = 'flow:established,to_server; content:"Content-Disposition|3a| attachment|3b| filename|3d 22|"; content:"' . $attribute['value'] . '|22|"; fast_pattern; content:"|0D 0A 0D 0A|"; within:8192;';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'tcp', // proto
'$EXTERNAL_NET', // src_ip
'any', // src_port
'<>', // direction
'->', // direction
'$SMTP_SERVERS', // dst_ip
'25', // dst_port
'Bad Email Attachment', // msg
@ -213,7 +226,8 @@ class NidsExportComponent extends Component {
public function hostnameRule($ruleFormat, $attribute, &$sid) {
$overruled = $this->checkWhitelist($attribute['value']);
$content = 'content:"' . $this->dnsNameToRawFormat($attribute['value'], 'hostname') . '"; nocase;';
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$content = 'content:"|01 00 00 01 00 00 00 00 00 00|"; depth:10; offset:2; content:"' . NidsExportComponent::dnsNameToRawFormat($attribute['value'], 'hostname') . '"; fast_pattern; nocase;';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'udp', // proto
@ -224,7 +238,7 @@ class NidsExportComponent extends Component {
'53', // dst_port
'Hostname: ' . $attribute['value'], // msg
$content, // rule_content
'', // tag
'', // tag
$sid, // sid
1 // rev
);
@ -238,26 +252,25 @@ class NidsExportComponent extends Component {
'any', // dst_ip
'53', // dst_port
'Hostname: ' . $attribute['value'], // msg
$content, // rule_content
'', // tag
$content. ' flow:established;', // rule_content
'', // tag
$sid, // sid
1 // rev
);
$sid++;
// also do http requests
// warning: only suricata compatible
$content = 'flow:to_server,established; content: "Host: ' . $attribute['value'] . '"; nocase; http_header; pcre: "/[^A-Za-z0-9-]' . preg_quote($attribute['value']) . '[^A-Za-z0-9-]/";';
$content = 'flow:to_server,established; content: "Host|3a| ' . $attribute['value'] . '"; nocase; http_header; pcre: "/[^A-Za-z0-9-\.]' . preg_quote($attribute['value']) . '[^A-Za-z0-9-\.]/H";';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'http', // proto
'tcp', // proto
'$HOME_NET', // src_ip
'any', // src_port
'->', // direction
'$EXTERNAL_NET', // dst_ip
'any', // dst_port
'$HTTP_PORTS', // dst_port
'Outgoing HTTP Hostname: ' . $attribute['value'], // msg
$content, // rule_content
'tag:session,600,seconds;', // tag
'tag:session,600,seconds;', // tag
$sid, // sid
1 // rev
);
@ -265,7 +278,8 @@ class NidsExportComponent extends Component {
public function domainRule($ruleFormat, $attribute, &$sid) {
$overruled = $this->checkWhitelist($attribute['value']);
$content = 'content:"' . $this->dnsNameToRawFormat($attribute['value']) . '"; nocase;';
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$content = 'content:"|01 00 00 01 00 00 00 00 00 00|"; depth:10; offset:2; content:"' . NidsExportComponent::dnsNameToRawFormat($attribute['value']) . '"; fast_pattern; nocase;';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'udp', // proto
@ -276,7 +290,7 @@ class NidsExportComponent extends Component {
'53', // dst_port
'Domain: ' . $attribute['value'], // msg
$content, // rule_content
'', // tag
'', // tag
$sid, // sid
1 // rev
);
@ -290,26 +304,25 @@ class NidsExportComponent extends Component {
'any', // dst_ip
'53', // dst_port
'Domain: ' . $attribute['value'], // msg
$content, // rule_content
'', // tag
$content. ' flow:established;', // rule_content
'', // tag
$sid, // sid
1 // rev
);
$sid++;
// also do http requests,
// warning: only suricata compatible
$content = 'flow:to_server,established; content: "Host:"; nocase; http_header; content:"' . $attribute['value'] . '"; nocase; http_header; pcre: "/[^A-Za-z0-9-]' . preg_quote($attribute['value']) . '[^A-Za-z0-9-]/";';
$content = 'flow:to_server,established; content: "Host|3a|"; nocase; http_header; content:"' . $attribute['value'] . '"; nocase; http_header; pcre: "/[^A-Za-z0-9-]' . preg_quote($attribute['value']) . '[^A-Za-z0-9-\.]/H";';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'http', // proto
'tcp', // proto
'$HOME_NET', // src_ip
'any', // src_port
'->', // direction
'$EXTERNAL_NET', // dst_ip
'any', // dst_port
'$HTTP_PORTS', // dst_port
'Outgoing HTTP Domain: ' . $attribute['value'], // msg
$content, // rule_content
'tag:session,600,seconds;', // tag
'tag:session,600,seconds;', // tag
$sid, // sid
1 // rev
);
@ -319,32 +332,50 @@ class NidsExportComponent extends Component {
// TODO in hindsight, an url should not be excluded given a host or domain name.
//$hostpart = parse_url($attribute['value'], PHP_URL_HOST);
//$overruled = $this->checkNames($hostpart);
// warning: only suricata compatible
$overruled = $this->checkWhitelist($attribute['value']);
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$content = 'flow:to_server,established; content:"' . $attribute['value'] . '"; nocase; http_uri;';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'http', // proto
'tcp', // proto
'$HOME_NET', // src_ip
'any', // src_port
'->', // direction
'$EXTERNAL_NET', // dst_ip
'any', // dst_port
'$HTTP_PORTS', // dst_port
'Outgoing HTTP URL: ' . $attribute['value'], // msg
$content, // rule_content
'tag:session,600,seconds;', // tag
'tag:session,600,seconds;', // tag
$sid, // sid
1 // rev
);
}
public function userAgentRule($ruleFormat, $attribute, &$sid) {
// TODO nids - write snort user-agent rule
$overruled = $this->checkWhitelist($attribute['value']);
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$content = 'flow:to_server,established; content:"' . $attribute['value'] . '"; http_header;';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'tcp', // proto
'$HOME_NET', // src_ip
'any', // src_port
'->', // direction
'$EXTERNAL_NET', // dst_ip
'$HTTP_PORTS', // dst_port
'Outgoing User-Agent: ' . $attribute['value'], // msg
$content, // rule_content
'tag:session,600,seconds;', // tag
$sid, // sid
1 // rev
);
}
public function snortRule($ruleFormat, $attribute, &$sid, $ruleFormatMsg, $ruleFormatReference) {
// LATER nids - test using lots of snort rules.
$tmpRule = $attribute['value'];
// LATER nids - test using lots of snort rules, some rules don't contain all the necessary to be a valid rule.
// store the value in the rule, but also strip out the newlines
$tmpRule = str_replace(array("\r","\n"), " ", $attribute['value']);
// rebuild the rule by overwriting the different keywords using preg_replace()
// sid - '/sid\s*:\s*[0-9]+\s*;/'
@ -388,15 +419,15 @@ class NidsExportComponent extends Component {
$this->rules[] = $tmpRule;
}
/**
* Converts a DNS name to a raw format usable in NIDS like Snort.
* example host: foobar.com becomes |00||06|foobar|03|com|00|
* example domain: foobar.com becomes |06|foobar|03|com|00|
* @param string $name dns name to be converted
* @param string $type the type of dns name - domain (default) or hostname
* @return string raw snort compatible format of the dns name
*/
public function dnsNameToRawFormat($name, $type='domain') {
/**
* Converts a DNS name to a raw format usable in NIDS like Snort.
* example host: foobar.com becomes |00||06|foobar|03|com|00|
* example domain: foobar.com becomes |06|foobar|03|com|00|
* @param string $name dns name to be converted
* @param string $type the type of dns name - domain (default) or hostname
* @return string raw snort compatible format of the dns name
*/
public static function dnsNameToRawFormat($name, $type='domain') {
$rawName = "";
if ('hostname' == $type) $rawName = '|00|';
// explode using the dot
@ -416,14 +447,14 @@ class NidsExportComponent extends Component {
return $rawName;
}
/**
* Converts a DNS name to a MS DNS log format.
* Practical usage is to use these strings to search in logfiles
* example: foobar.com becomes (6)foobar(3)com(0)
* @param string $name dns name to be converted
* @return string raw snort compatible format of the dns name
*/
public function dnsNameToMSDNSLogFormat($name) {
/**
* Converts a DNS name to a MS DNS log format.
* Practical usage is to use these strings to search in logfiles
* example: foobar.com becomes (6)foobar(3)com(0)
* @param string $name dns name to be converted
* @return string raw snort compatible format of the dns name
*/
public static function dnsNameToMSDNSLogFormat($name) {
$rawName = "";
// in MS DNS log format we can't use (0) to distinguish between hostname and domain (including subdomains)
// explode using the dot
@ -438,10 +469,27 @@ class NidsExportComponent extends Component {
}
// put all together
$rawName .= '(0)';
// and append |00| to terminate the name
// and append (0) to terminate the name
return $rawName;
}
/**
* 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) {
foreach ($this->whitelist as $wlitem) {
if (preg_match($wlitem, $value)) {

View File

@ -0,0 +1,17 @@
<?php
App::uses('NidsExportComponent', 'Controller/Component');
class NidsSnortExportComponent extends NidsExportComponent {
public function export($items, $startSid) {
// set the specific format
$this->format = 'snort';
// call the generic function
return parent::export($items, $startSid);
}
// below overwrite functions from NidsExportComponent
}

View File

@ -0,0 +1,167 @@
<?php
App::uses('NidsExportComponent', 'Controller/Component');
class NidsSuricataExportComponent extends NidsExportComponent {
public function export($items, $startSid) {
// set the specific format
$this->format = 'suricata';
// call the generic function
return parent::export($items, $startSid);
}
// below overwrite functions from NidsExportComponent
public function hostnameRule($ruleFormat, $attribute, &$sid) {
$overruled = $this->checkWhitelist($attribute['value']);
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$content = 'content:"|01 00 00 01 00 00 00 00 00 00|"; depth:10; offset:2; content:"' . NidsExportComponent::dnsNameToRawFormat($attribute['value'], 'hostname') . '"; fast_pattern; nocase;';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'udp', // proto
'any', // src_ip
'any', // src_port
'->', // direction
'any', // dst_ip
'53', // dst_port
'Hostname: ' . $attribute['value'], // msg
$content, // rule_content
'', // tag
$sid, // sid
1 // rev
);
$sid++;
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'tcp', // proto
'any', // src_ip
'any', // src_port
'->', // direction
'any', // dst_ip
'53', // dst_port
'Hostname: ' . $attribute['value'], // msg
$content. ' flow:established;', // rule_content
'', // tag
$sid, // sid
1 // rev
);
$sid++;
// also do http requests
// warning: only suricata compatible
$content = 'flow:to_server,established; content: "Host|3a| ' . $attribute['value'] . '"; fast_pattern; nocase; http_header; pcre: "/[^A-Za-z0-9-\.]' . preg_quote($attribute['value']) . '[^A-Za-z0-9-\.]/H";';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'http', // proto
'$HOME_NET', // src_ip
'any', // src_port
'->', // direction
'$EXTERNAL_NET', // dst_ip
'any', // dst_port
'Outgoing HTTP Hostname: ' . $attribute['value'], // msg
$content, // rule_content
'tag:session,600,seconds;', // tag
$sid, // sid
1 // rev
);
}
public function domainRule($ruleFormat, $attribute, &$sid) {
$overruled = $this->checkWhitelist($attribute['value']);
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$content = 'content:"|01 00 00 01 00 00 00 00 00 00|"; depth:10; offset:2; content:"' . NidsExportComponent::dnsNameToRawFormat($attribute['value']) . '"; fast_pattern; nocase;';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'udp', // proto
'any', // src_ip
'any', // src_port
'->', // direction
'any', // dst_ip
'53', // dst_port
'Domain: ' . $attribute['value'], // msg
$content, // rule_content
'', // tag
$sid, // sid
1 // rev
);
$sid++;
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'tcp', // proto
'any', // src_ip
'any', // src_port
'->', // direction
'any', // dst_ip
'53', // dst_port
'Domain: ' . $attribute['value'], // msg
$content. ' flow:established;', // rule_content
'', // tag
$sid, // sid
1 // rev
);
$sid++;
// also do http requests,
// warning: only suricata compatible
$content = 'flow:to_server,established; content: "Host|3a|"; nocase; http_header; content:"' . $attribute['value'] . '"; fast_pattern; nocase; http_header; pcre: "/[^A-Za-z0-9-]' . preg_quote($attribute['value']) . '[^A-Za-z0-9-\.]/H";';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'http', // proto
'$HOME_NET', // src_ip
'any', // src_port
'->', // direction
'$EXTERNAL_NET', // dst_ip
'any', // dst_port
'Outgoing HTTP Domain: ' . $attribute['value'], // msg
$content, // rule_content
'tag:session,600,seconds;', // tag
$sid, // sid
1 // rev
);
}
public function urlRule($ruleFormat, $attribute, &$sid) {
// TODO in hindsight, an url should not be excluded given a host or domain name.
//$hostpart = parse_url($attribute['value'], PHP_URL_HOST);
//$overruled = $this->checkNames($hostpart);
// warning: only suricata compatible
$overruled = $this->checkWhitelist($attribute['value']);
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$content = 'flow:to_server,established; content:"' . $attribute['value'] . '"; fast_pattern; nocase; http_uri;';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'http', // proto
'$HOME_NET', // src_ip
'any', // src_port
'->', // direction
'$EXTERNAL_NET', // dst_ip
'any', // dst_port
'Outgoing HTTP URL: ' . $attribute['value'], // msg
$content, // rule_content
'tag:session,600,seconds;', // tag
$sid, // sid
1 // rev
);
}
public function userAgentRule($ruleFormat, $attribute, &$sid) {
$overruled = $this->checkWhitelist($attribute['value']);
$attribute['value'] = NidsExportComponent::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
// warning: only suricata compatible
$content = 'flow:to_server,established; content:"' . $attribute['value'] . '"; fast_pattern; http_user_agent;';
$this->rules[] = sprintf($ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
'http', // proto
'$HOME_NET', // src_ip
'any', // src_port
'->', // direction
'$EXTERNAL_NET', // dst_ip
'any', // dst_port
'Outgoing User-Agent: ' . $attribute['value'], // msg
$content, // rule_content
'tag:session,600,seconds;', // tag
$sid, // sid
1 // rev
);
}
}

View File

@ -20,7 +20,7 @@ class EventsController extends AppController {
'RequestHandler',
'HidsMd5Export',
'HidsSha1Export',
'NidsExport',
//'NidsSuricataExport',
'IOCExport',
'IOCImport'
);
@ -29,7 +29,7 @@ class EventsController extends AppController {
'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.
'order' => array(
'Event.id' => 'DESC'
'Event.timestamp' => 'DESC'
),
);
@ -45,6 +45,7 @@ class EventsController extends AppController {
$this->Auth->allow('hids_sha1');
$this->Auth->allow('text');
$this->Auth->allow('dot');
$this->Auth->allow('restSearch');
// TODO Audit, activate logable in a Controller
if (count($this->uses) && $this->{$this->modelClass}->Behaviors->attached('SysLogLogable')) {
@ -263,7 +264,7 @@ class EventsController extends AppController {
}
$this->Session->write('pivot_thread', $pivot);
}
private function __insertPivot($pivot, $oldId, $newPivot, $depth) {
$depth++;
if ($pivot['id'] == $oldId) {
@ -276,7 +277,7 @@ class EventsController extends AppController {
}
return $pivot;
}
private function __checkForPivot($pivot, $id) {
if ($id == $pivot['id']) return true;
foreach ($pivot['children'] as $k => $v) {
@ -286,7 +287,7 @@ class EventsController extends AppController {
}
return false;
}
private function __arrangePivotVertical(&$pivot) {
if (empty($pivot)) return null;
$max = count($pivot['children']) - 1;
@ -300,7 +301,7 @@ class EventsController extends AppController {
}
return $temp;
}
public function removePivot($id, $eventId, $self = false) {
$pivot = $this->Session->read('pivot_thread');
if ($pivot['id'] == $id) {
@ -314,7 +315,7 @@ class EventsController extends AppController {
$pivot = $this->__arrangePivotVertical($pivot);
$this->redirect(array('controller' => 'events', 'action' => 'view', $eventId, true, $eventId));
}
private function __removeChildren(&$pivot, $id) {
if ($pivot['id'] == $id) {
$pivot['children'] = array();
@ -324,7 +325,7 @@ class EventsController extends AppController {
}
}
}
private function __doRemove(&$pivot, $id) {
foreach ($pivot['children'] as $k => $v) {
if ($v['id'] == $id) {
@ -336,7 +337,7 @@ class EventsController extends AppController {
}
return $pivot;
}
private function __setDeletable(&$pivot, $id, $root=false) {
if ($pivot['id'] == $id && !$root) {
$pivot['deletable'] = false;
@ -349,123 +350,7 @@ class EventsController extends AppController {
}
return !$pivot['deletable'];
}
/*
public function view($id = null) {
// If the length of the id provided is 36 then it is most likely a Uuid - find the id of the event, change $id to it and proceed to read the event as if the ID was entered.
$perm_publish = $this->userRole['perm_publish'];
if (strlen($id) == 36) {
$this->Event->recursive = -1;
$temp = $this->Event->findByUuid($id);
if ($temp == null) throw new NotFoundException(__('Invalid event'));
$id = $temp['Event']['id'];
}
$isSiteAdmin = $this->_isSiteAdmin();
$this->Event->id = $id;
if(!$this->Event->exists()) {
throw new NotFoundException(__('Invalid event, it already exists.'));
}
$this->Event->recursive = 2;
$this->Event->contain('Attribute', 'ShadowAttribute', 'User.email');
$this->Event->read();
$myEvent = true;
if (!$isSiteAdmin) {
// check private
if (($this->Event->data['Event']['distribution'] == 0) && ($this->Event->data['Event']['org'] != $this->Auth->user('org'))) {
$this->Session->setFlash(__('Invalid event.'));
$this->redirect(array('controller' => 'events', 'action' => 'index'));
}
}
if ($this->Event->data['Event']['org'] != $this->Auth->user('org')) {
$myEvent = false;
}
// Now that we're loaded the event and made sure that we can actually see it, let's do 2 thngs:
// run through each attribute and unset it if it's private and we're not an admin or from the owner org of the event
// if we didn't unset the attribute, rearrange the shadow attributes
foreach ($this->Event->data['Attribute'] as $key => &$attribute) {
if (!$isSiteAdmin && !$myEvent && ($attribute['distribution'] == 0)) {
unset($this->Event->data['Attribute'][$key]);
} else {
if (!isset($attribute['ShadowAttribute'])) $attribute['ShadowAttribute'] = array();
foreach ($this->Event->data['ShadowAttribute'] as $k => &$sa) {
if ($sa['old_id'] == $attribute['id']) {
$this->Event->data['Attribute'][$key]['ShadowAttribute'][] = $sa;
unset($this->Event->data['ShadowAttribute'][$k]);
}
}
}
}
// since we unset some attributes and shadowattributes, let's reindex them.
$this->Event->data['ShadowAttribute'] = array_values($this->Event->data['ShadowAttribute']);
$this->Event->data['Attribute'] = array_values($this->Event->data['Attribute']);
$this->set('analysisLevels', $this->Event->analysisLevels);
$relatedEvents = $this->Event->getRelatedEvents($this->Auth->user());
$relatedAttributes = $this->Event->getRelatedAttributes($this->Auth->user());
$this->loadModel('Attribute');
if ($this->_isRest()) {
foreach ($this->Event->data['Attribute'] as &$attribute) {
// for REST requests also add the encoded attachment
if ($this->Attribute->typeIsAttachment($attribute['type'])) {
// LATER check if this has a serious performance impact on XML conversion and memory usage
$encodedFile = $this->Attribute->base64EncodeAttachment($attribute);
$attribute['data'] = $encodedFile;
}
}
}
// set up the ShadowAttributes for the view - the only shadow attributes that should be passed to the view are the ones that the user is eligible to see
// This means: Proposals of other organisations to own events, if the user is a publisher
// Also: proposals made by the current user's organisation
if (!$this->_isRest()) {
foreach ($this->Event->data['Attribute'] as &$attribute) {
// if the user is of the same org as the event and has publishing rights, just show everything
if (($this->Auth->user('org') != $this->Event->data['Event']['org'] || !$perm_publish) && !$this->_isSiteAdmin()) {
$counter = 0;
foreach ($attribute['ShadowAttribute'] as &$shadow) {
if ($shadow['org'] != $this->Auth->user('org')) unset($attribute['ShadowAttribute'][$counter]);
$counter++;
}
}
}
}
// params for the jQuery RESTfull interface
$this->set('authkey', $this->Auth->user('authkey'));
$this->set('baseurl', Configure::read('CyDefSIG.baseurl'));
$this->set('relatedAttributes', $relatedAttributes);
// passing decriptions for model fields
$this->set('eventDescriptions', $this->Event->fieldDescriptions);
$this->set('attrDescriptions', $this->Attribute->fieldDescriptions);
$this->set('event', $this->Event->data);
if(isset($this->Event->data['ShadowAttribute'])) {
$this->set('remaining', $this->Event->data['ShadowAttribute']);
}
$this->set('relatedEvents', $relatedEvents);
$this->set('categories', $this->Attribute->validate['category']['rule'][1]);
// passing type and category definitions (explanations)
$this->set('typeDefinitions', $this->Attribute->typeDefinitions);
$this->set('categoryDefinitions', $this->Attribute->categoryDefinitions);
// combobox for analysis
$this->set('distributionDescriptions', $this->Event->distributionDescriptions);
$this->set('distributionLevels', $this->Event->distributionLevels);
// combobox for analysis
$analysiss = $this->Event->validate['analysis']['rule'][1];
$analysiss = $this->_arrayToValuesIndexArray($analysiss);
$this->set('analysiss', $analysiss);
// tooltip for analysis
$this->set('analysisDescriptions', $this->Event->analysisDescriptions);
$this->set('analysisLevels', $this->Event->analysisLevels);
}
*/
/**
* add method
@ -1497,7 +1382,7 @@ class EventsController extends AppController {
// Grab an event or a list of events for the event view or any of the XML exports. The returned object includes an array of events (or an array that only includes a single event if an ID was given)
// Included with the event are the attached attributes, shadow attributes, related events, related attribute information for the event view and the creating user's email address where appropriate
private function __fetchEvent($eventid = null, $idList = null) {
private function __fetchEvent($eventid = null, $idList = null, $orgFromFetch = null) {
if (isset($eventid)) {
$this->Event->id = $eventid;
if (!$this->Event->exists()) {
@ -1507,11 +1392,22 @@ class EventsController extends AppController {
} else {
$conditions = array();
}
// if we come from automation, we may not be logged in - instead we used an auth key in the URL.
if (!empty($orgFromFetch)) {
$org = $orgFromFetch;
if ($orgFromFetch == 'ADMIN') $isSiteAdmin = true;
else $isSiteAdmin = false;
} else {
$org = $this->_checkOrg();
$isSiteAdmin = $this->_isSiteAdmin();
}
$conditionsAttributes = array();
$conditionsShadowAttributes = array();
//restricting to non-private or same org if the user is not a site-admin.
if (!$this->_isSiteAdmin()) {
$org = $this->_checkOrg();
if (!$isSiteAdmin) {
if (!empty($orgFromFetch)) $org = $orgFromFetch;
else $org = $this->_checkOrg();
$conditions['AND']['OR'] = array(
'Event.distribution >' => 0,
'Event.org LIKE' => $org
@ -1527,10 +1423,8 @@ class EventsController extends AppController {
array('(SELECT events.org FROM events WHERE events.id = ShadowAttribute.event_id) LIKE' => $org),
array('ShadowAttribute.org LIKE' => $org),
);
}
if ($idList) {
$conditions['AND'][] = array('Event.id' => $idList);
}
@ -1559,7 +1453,7 @@ class EventsController extends AppController {
),
)
);
if ($this->_isAdmin()) $params['contain']['User'] = array('fields' => 'email');
if ($isSiteAdmin) $params['contain']['User'] = array('fields' => 'email');
$results = $this->Event->find('all', $params);
// Do some refactoring with the event
foreach ($results as $eventKey => &$event) {
@ -1584,7 +1478,14 @@ class EventsController extends AppController {
return $results;
}
public function nids($key) {
public function nids($format = 'suricata', $key = '') {
// backwards compatibility, swap key and format
if ($format != 'snort' && $format != 'suricata') {
$key = $format;
$format = 'suricata'; // default format
}
if ($key != 'download') {
$this->response->type('txt'); // set the content type
$this->header('Content-Disposition: inline; filename="misp.rules"');
@ -1627,7 +1528,17 @@ class EventsController extends AppController {
unset($this->Attribute->virtualFields['category_order']); // not needed for IDS export and speeds things up
$items = $this->Attribute->find('all', $params);
// export depending of the requested type
switch ($format) {
case 'suricata':
$this->NidsExport = $this->Components->load('NidsSuricataExport');
break;
case 'snort':
$this->NidsExport = $this->Components->load('NidsSnortExport');
break;
}
$rules = $this->NidsExport->export($items, $user['User']['nids_sid']);
$this->set('rules', $rules);
}
@ -2217,7 +2128,73 @@ class EventsController extends AppController {
$this->set('results', $results);
$this->render('xml');
}
// Use the rest interface to search for attributes or events. Usage:
// MISP-base-url/events/restSearch/[api-key]/[value]/[type]/[category]/[orgc]
// value, type, category, orgc are optional
// target can be either "event" or "attribute"
// the last 4 fields accept the following operators:
// && - you can use && between two search values to put a logical OR between them. for value, 1.1.1.1&&2.2.2.2 would find attributes with the value being either of the two.
// ! - you can negate a search term. For example: google.com&&!mail would search for all attributes with value google.com but not ones that include mail. www.google.com would get returned, mail.google.com wouldn't.
public function restSearch($key, $value=null, $type=null, $category=null, $org=null) {
$user = $this->checkAuthUser($key);
if (!$user) {
throw new UnauthorizedException('This authentication key is not authorized to be used for exports. Contact your administrator.');
}
$this->response->type('xml'); // set the content type
$this->layout = 'xml/default';
$this->header('Content-Disposition: download; filename="misp.search.events.results.xml"');
$conditions['AND'] = array();
$subcondition = array();
$this->loadModel('Attribute');
// add the values as specified in the 2nd parameter to the conditions
$values = explode('&&', $value);
$parameters = array('value', 'type', 'category', 'org');
foreach ($parameters as $k => $param) {
if (isset(${$parameters[$k]})) {
$elements = explode('&&', ${$parameters[$k]});
foreach($elements as $v) {
if (substr($v, 0, 1) == '!') {
$subcondition['AND'][] = array('Attribute.' . $parameters[$k] . ' NOT LIKE' => '%'.substr($v, 1).'%');
} else {
$subcondition['OR'][] = array('Attribute.' . $parameters[$k] . ' LIKE' => '%'.$v.'%');
}
}
array_push ($conditions['AND'], $subcondition);
$subcondition = array();
}
}
// If we are looking for an attribute, we want to retrieve some extra data about the event to be able to check for the permissions.
if (!$user['User']['siteAdmin']) {
$temp = array();
$temp['AND'] = array('Event.distribution >' => 0, 'Attribute.distribution >' => 0);
$subcondition['OR'][] = $temp;
$subcondition['OR'][] = array('Event.org' => $user['User']['org']);
array_push($conditions['AND'], $subcondition);
}
$params = array(
'conditions' => $conditions,
'fields' => array('Attribute.event_id'),
);
$attributes = $this->Attribute->find('all', $params);
$eventIds = array();
foreach ($attributes as $attribute) {
if (!in_array($attribute['Attribute']['event_id'], $eventIds)) $eventIds[] = $attribute['Attribute']['event_id'];
}
if (!empty($eventIds)) {
$results = $this->__fetchEvent(null, $eventIds, $user['User']['org']);
} else {
throw new NotFoundException('No matches.');
}
$this->loadModel('Whitelist');
$results = $this->Whitelist->removeWhitelistedFromArray($results, true);
$this->set('results', $results);
}
public function downloadOpenIOCEvent($eventid) {
// return a downloadable text file called misp.openIOC.<eventId>.ioc for individual events

View File

@ -93,6 +93,7 @@ class ShadowAttribute extends AppModel {
public $typeDefinitions = array(
'md5' => array('desc' => 'A checksum in md5 format', 'formdesc' => "You are encouraged to use filename|md5 instead. <br/>A checksum in md5 format, only use this if you don't know the correct filename"),
'sha1' => array('desc' => 'A checksum in sha1 format', 'formdesc' => "You are encouraged to use filename|sha1 instead. <br/>A checksum in sha1 format, only use this if you don't know the correct filename"),
'sha256' => array('desc' => 'A checksum in sha256 format', 'formdesc' => "You are encouraged to use filename|sha256 instead. A checksum in sha256 format, o nly use this if you don't know the correct filename"),
'filename' => array('desc' => 'Filename'),
'filename|md5' => array('desc' => 'A filename and an md5 hash separated by a |', 'formdesc' => "A filename and an md5 hash separated by a | (no spaces)"),
'filename|sha1' => array('desc' => 'A filename and an sha1 hash separated by a |', 'formdesc' => "A filename and an sha1 hash separated by a | (no spaces)"),
@ -105,7 +106,8 @@ class ShadowAttribute extends AppModel {
'email-subject' => array('desc' => "The subject of the email"),
'email-attachment' => array('desc' => "File name of the email attachment."),
'url' => array('desc' => 'url'),
'user-agent' => array('desc' => "The user-agent used by the malware in the HTTP request."),
'http-method' => array('desc' => "HTTP method used by the malware (e.g. POST, GET, ...)."),
'user-agent' => array('desc' => "The user-agent used by the malware in the HTTP request."),
'regkey' => array('desc' => "Registry key or value"),
'regkey|value' => array('desc' => "Registry value + data separated by |"),
'AS' => array('desc' => 'Autonomous system'),
@ -120,6 +122,8 @@ class ShadowAttribute extends AppModel {
'link' => array('desc' => 'Link to an external information'),
'comment' => array('desc' => 'Comment or description in a human language', 'formdesc' => 'Comment or description in a human language. <br/> This will not be correlated with other attributes (NOT IMPLEMENTED YET)'),
'text' => array('desc' => 'Name, ID or a reference'),
'named pipe' => array('desc' => 'Named pipe, use the format \\.\pipe\<PipeName>'),
'mutex' => array('desc' => 'Mutex, use the format \BaseNamedObjects\<Mutex>'),
'other' => array('desc' => 'Other attribute')
);
@ -137,16 +141,16 @@ class ShadowAttribute extends AppModel {
'Payload delivery' => array(
'desc' => 'Information about how the malware is delivered',
'formdesc' => 'Information about the way the malware payload is initially delivered, <br/>for example information about the email or web-site, vulnerability used, originating IP etc. <br/>Malware sample itself should be attached here.',
'types' => array('md5', 'sha1', 'filename', 'filename|md5', 'filename|sha1', 'ip-src', 'ip-dst', 'hostname', 'domain', 'email-src', 'email-dst', 'email-subject', 'email-attachment', 'url', 'ip-dst', 'user-agent', 'AS', 'pattern-in-file', 'pattern-in-traffic', 'yara', 'attachment', 'malware-sample', 'link', 'comment', 'text', 'vulnerability', 'other')
'types' => array('md5', 'sha1', 'sha256', 'filename', 'filename|md5', 'filename|sha1', 'filename|sha256', 'ip-src', 'ip-dst', 'hostname', 'domain', 'email-src', 'email-dst', 'email-subject', 'email-attachment', 'url', 'ip-dst', 'user-agent', 'http-method', 'AS', 'pattern-in-file', 'pattern-in-traffic', 'yara', 'attachment', 'malware-sample', 'link', 'comment', 'text', 'vulnerability', 'other')
),
'Artifacts dropped' => array(
'desc' => 'Any artifact (files, registry keys etc.) dropped by the malware or other modifications to the system',
'types' => array('md5', 'sha1', 'filename', 'filename|md5', 'filename|sha1', 'regkey', 'regkey|value', 'pattern-in-file', 'pattern-in-memory', 'yara', 'attachment', 'malware-sample', 'comment', 'text', 'other')
'types' => array('md5', 'sha1', 'sha256', 'filename', 'filename|md5', 'filename|sha256', 'filename|sha1', 'regkey', 'regkey|value', 'pattern-in-file', 'pattern-in-memory', 'yara', 'attachment', 'malware-sample', 'comment', 'text', 'other', 'named pipe', 'mutex')
),
'Payload installation' => array(
'desc' => 'Info on where the malware gets installed in the system',
'formdesc' => 'Location where the payload was placed in the system and the way it was installed.<br/>For example, a filename|md5 type attribute can be added here like this:<br/>c:\\windows\\system32\\malicious.exe|41d8cd98f00b204e9800998ecf8427e.',
'types' => array('md5', 'sha1', 'filename', 'filename|md5', 'filename|sha1', 'pattern-in-file', 'pattern-in-traffic', 'pattern-in-memory', 'yara', 'vulnerability', 'attachment', 'malware-sample', 'comment', 'text', 'other')
'types' => array('md5', 'sha1', 'sha256', 'filename', 'filename|md5', 'filename|sha1', 'filename|sha256', 'pattern-in-file', 'pattern-in-traffic', 'pattern-in-memory', 'yara', 'vulnerability', 'attachment', 'malware-sample', 'comment', 'text', 'other')
),
'Persistence mechanism' => array(
'desc' => 'Mechanisms used by the malware to start at boot',
@ -155,7 +159,7 @@ class ShadowAttribute extends AppModel {
),
'Network activity' => array(
'desc' => 'Information about network traffic generated by the malware',
'types' => array('ip-src', 'ip-dst', 'hostname', 'domain', 'email-dst', 'url', 'user-agent', 'AS', 'snort', 'pattern-in-file', 'pattern-in-traffic', 'attachment', 'comment', 'text', 'other')
'types' => array('ip-src', 'ip-dst', 'hostname', 'domain', 'email-dst', 'url', 'user-agent', 'http-method','AS', 'snort', 'pattern-in-file', 'pattern-in-traffic', 'attachment', 'comment', 'text', 'other')
),
'Payload type' => array(
'desc' => 'Information about the final payload(s)',
@ -169,7 +173,7 @@ class ShadowAttribute extends AppModel {
'External analysis' => array(
'desc' => 'Any other result from additional analysis of the malware like tools output',
'formdesc' => 'Any other result from additional analysis of the malware like tools output<br/>Examples: pdf-parser output, automated sandbox analysis, reverse engineering report.',
'types' => array('md5', 'sha1', 'filename', 'filename|md5', 'filename|sha1', 'ip-src', 'ip-dst', 'hostname', 'domain', 'url', 'user-agent', 'regkey', 'regkey|value', 'AS', 'snort', 'pattern-in-file', 'pattern-in-traffic', 'pattern-in-memory', 'vulnerability', 'attachment', 'malware-sample', 'link', 'comment', 'text', 'other')
'types' => array('md5', 'sha1', 'sha256', 'filename', 'filename|md5', 'filename|sha1', 'filename|sha256', 'ip-src', 'ip-dst', 'hostname', 'domain', 'url', 'user-agent', 'http-method', 'regkey', 'regkey|value', 'AS', 'snort', 'pattern-in-file', 'pattern-in-traffic', 'pattern-in-memory', 'vulnerability', 'attachment', 'malware-sample', 'link', 'comment', 'text', 'other')
),
'Other' => array(
'desc' => 'Attributes that are not part of any other category',

View File

@ -0,0 +1,13 @@
<?php
$xmlArray = array();
foreach ($results as $k => $v) {
unset (
$results[$k]['Event'],
$results[$k]['Attribute']['value1'],
$results[$k]['Attribute']['value2'],
$results[$k]['Attribute']['category_order']
);
$xmlArray['response']['Attribute'][] = $results[$k]['Attribute'];
}
$xmlObject = Xml::fromArray($xmlArray, array('format' => 'tags'));
echo $xmlObject->asXML();

View File

@ -0,0 +1,12 @@
<?php
$xmlArray = array();
foreach ($results as $k => $v) {
unset (
$results[$k]['value1'],
$results[$k]['value2'],
$results[$k]['category_order']
);
$xmlArray['response']['Attribute'][] = $results[$k];
}
$xmlObject = Xml::fromArray($xmlArray, array('format' => 'tags'));
echo $xmlObject->asXML();

View File

@ -0,0 +1,13 @@
<?php
$xmlArray = array();
foreach ($results as $k => $v) {
unset (
$results[$k]['Event'],
$results[$k]['Attribute']['value1'],
$results[$k]['Attribute']['value2'],
$results[$k]['Attribute']['category_order']
);
$xmlArray['response']['Attribute'][] = $results[$k]['Attribute'];
}
$xmlObject = Xml::fromArray($xmlArray, array('format' => 'tags'));
echo $xmlObject->asXML();

View File

@ -0,0 +1,12 @@
<?php
$xmlArray = array();
foreach ($results as $k => $v) {
unset (
$results[$k]['value1'],
$results[$k]['value2'],
$results[$k]['category_order']
);
$xmlArray['response']['Attribute'][] = $results[$k];
}
$xmlObject = Xml::fromArray($xmlArray, array('format' => 'tags'));
echo $xmlObject->asXML();

View File

@ -17,10 +17,11 @@ You can <?php echo $this->Html->link('reset', array('controller' => 'users', 'ac
<p>Also check out the <?php echo $this->Html->link(__('User Guide', true), array('controller' => 'pages', 'action' => 'display', 'using_the_system', '#' => 'rest')); ?> to read about the REST API.</p>
<p></p>
<h3>NIDS signatures export</h3>
<h3>NIDS rules export</h3>
<p>Automatic export of all network related attributes is available under the Snort rule format. Only <em>published</em> events and attributes marked as <em>IDS Signature</em> are exported.</p>
<p>You can configure your tools to automatically download the following file:</p>
<pre><?php echo Configure::read('CyDefSIG.baseurl');?>/events/nids/<?php echo $me['authkey']; ?></pre>
<pre><?php echo Configure::read('CyDefSIG.baseurl');?>/events/nids/suricata/<?php echo $me['authkey']."\n"; ?>
<?php echo Configure::read('CyDefSIG.baseurl');?>/events/nids/snort/<?php echo $me['authkey']; ?></pre>
<p></p>
<p>Administration is able to maintain a white-list containing host, domain name and IP numbers to exclude from the NIDS export.</p>
@ -45,16 +46,51 @@ foreach ($sigTypes as $sigType) {
</pre>
<p></p>
<h3>Saved search XML export</h3>
<p>We plan to make it possible to export data using searchpatterns.<br/>
This would enable you to export:</p>
<ul>
<li>only your own attributes</li>
<li>date ranges</li>
<li>only specific attribute types (domain)</li>
<li>...</li>
</ul>
<h3>RESTful searches with XML result export</h3>
<p>It is possible to search the database for attributes based on a list of criteria. </p>
<p>To return an event with all of its attributes, relations, shadowAttributes, use the following syntax:</p>
<pre>
<?php
echo Configure::read('CyDefSIG.baseurl').'/events/restSearch/'.$me['authkey'].'/[value]/[type]/[category]/[org]';
?>
</pre>
<p>To just return a list of attributes, use the following syntax:</p>
<pre>
<?php
echo Configure::read('CyDefSIG.baseurl').'/attributes/restSearch/'.$me['authkey'].'/[value]/[type]/[category]/[org]';
?>
</pre>
<p>value, type, category and org are optional. It is possible to search for several terms in each category by joining them with the '&amp;&amp;' operator. It is also possible to negate a term with the '!' operator.
For example, in order to search for all attributes created by your organisation that contain 192.168 or 127.0 but not 0.1 and are of the type ip-src use the following syntax:</p>
<pre>
<?php
echo Configure::read('CyDefSIG.baseurl').'/attributes/restSearch/'.$me['authkey'].'/192.168&&127.0&&!0.1/ip-src/null/' . $me['org'];
?>
</pre>
<h3>Export attributes of event with specified type as XML</h3>
<p>If you want to export all attributes of a pre-defined type that belong to an event, use the following syntax:</p>
<pre>
<?php
echo Configure::read('CyDefSIG.baseurl').'/attributes/returnAttributes/'.$me['authkey'].'/[id]/[type]/[sigOnly]';
?>
</pre>
<p>sigOnly is an optional flag that will block all attributes from being exported that don't have the IDS flag turned on.
It is possible to search for several types with the '&amp;&amp;' operator and to exclude values with the '!' operator.
For example, to get all IDS signature attributes of type md5 and sha256, but not filename|md5 and filename|sha256 from event 25, use the following: </p>
<pre>
<?php
echo Configure::read('CyDefSIG.baseurl').'/attributes/returnAttributes/'.$me['authkey'].'/25/md5&&sha256&&!filename/true';
?>
</pre>
<h3>Download attachment or malware sample</h3>
<p>If you know the attribute ID of a malware-sample or an attachment, you can download it with the following syntax:</p>
<pre>
<?php
echo Configure::read('CyDefSIG.baseurl').'/attributes/downloadAttachment/'.$me['authkey'].'/[Attribute_id]';
?>
</pre>
</div>
<?php
echo $this->element('side_menu', array('menuList' => 'event-collection', 'menuItem' => 'automation'));

View File

@ -28,7 +28,8 @@
</div>
<div class="row bottom-buffer">
<div class="span3">
<?php echo $this->Html->link('Download NIDS signatures', array('action' => 'nids', 'download'), array('class' => 'btn btn-block full-width')); ?>
<?php echo $this->Html->link('Download Suricata rules', array('action' => 'nids', 'suricata', 'download'), array('class' => 'btn btn-block full-width')); ?>
<?php echo $this->Html->link('Download Snort rules', array('action' => 'nids', 'snort', 'download'), array('class' => 'btn btn-block full-width')); ?>
</div>
<div class="span9">Click this to download all network related attributes that you
have access to under the Snort rule format. Only <em>published</em>
@ -65,4 +66,4 @@
</div>
<?php
echo $this->element('side_menu', array('menuList' => 'event-collection', 'menuItem' => 'export'));
?>
?>

View File

@ -0,0 +1,45 @@
<?php
$xmlArray = array();
foreach ($results as $result) {
$result['Event']['Attribute'] = $result['Attribute'];
$result['Event']['ShadowAttribute'] = $result['ShadowAttribute'];
$result['Event']['RelatedEvent'] = $result['RelatedEvent'];
//
// cleanup the array from things we do not want to expose
//
unset($result['Event']['user_id']);
// hide the org field is we are not in showorg mode
if ('true' != Configure::read('CyDefSIG.showorg') && !$isSiteAdmin) {
unset($result['Event']['org']);
unset($result['Event']['orgc']);
unset($result['Event']['from']);
}
// remove value1 and value2 from the output and remove invalid utf8 characters for the xml parser
foreach ($result['Event']['Attribute'] as $key => $value) {
$result['Event']['Attribute'][$key]['value'] = preg_replace ('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $result['Event']['Attribute'][$key]['value']);
unset($result['Event']['Attribute'][$key]['value1']);
unset($result['Event']['Attribute'][$key]['value2']);
unset($result['Event']['Attribute'][$key]['category_order']);
}
// remove invalid utf8 characters for the xml parser
foreach($result['Event']['ShadowAttribute'] as $key => $value) {
$result['Event']['ShadowAttribute'][$key]['value'] = preg_replace ('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $result['Event']['ShadowAttribute'][$key]['value']);
}
if (isset($result['Event']['RelatedEvent'])) {
foreach ($result['Event']['RelatedEvent'] as $key => $value) {
unset($result['Event']['RelatedEvent'][$key]['user_id']);
if ('true' != Configure::read('CyDefSIG.showorg') && !$isAdmin) {
unset($result['Event']['RelatedEvent'][$key]['org']);
unset($result['Event']['RelatedEvent'][$key]['orgc']);
}
}
}
$xmlArray['response']['Event'][] = $result['Event'];
}
$xmlObject = Xml::fromArray($xmlArray, array('format' => 'tags'));
echo $xmlObject->asXML();

View File

@ -0,0 +1,45 @@
<?php
$xmlArray = array();
foreach ($results as $result) {
$result['Event']['Attribute'] = $result['Attribute'];
$result['Event']['ShadowAttribute'] = $result['ShadowAttribute'];
$result['Event']['RelatedEvent'] = $result['RelatedEvent'];
//
// cleanup the array from things we do not want to expose
//
unset($result['Event']['user_id']);
// hide the org field is we are not in showorg mode
if ('true' != Configure::read('CyDefSIG.showorg') && !$isSiteAdmin) {
unset($result['Event']['org']);
unset($result['Event']['orgc']);
unset($result['Event']['from']);
}
// remove value1 and value2 from the output and remove invalid utf8 characters for the xml parser
foreach ($result['Event']['Attribute'] as $key => $value) {
$result['Event']['Attribute'][$key]['value'] = preg_replace ('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $result['Event']['Attribute'][$key]['value']);
unset($result['Event']['Attribute'][$key]['value1']);
unset($result['Event']['Attribute'][$key]['value2']);
unset($result['Event']['Attribute'][$key]['category_order']);
}
// remove invalid utf8 characters for the xml parser
foreach($result['Event']['ShadowAttribute'] as $key => $value) {
$result['Event']['ShadowAttribute'][$key]['value'] = preg_replace ('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $result['Event']['ShadowAttribute'][$key]['value']);
}
if (isset($result['Event']['RelatedEvent'])) {
foreach ($result['Event']['RelatedEvent'] as $key => $value) {
unset($result['Event']['RelatedEvent'][$key]['user_id']);
if ('true' != Configure::read('CyDefSIG.showorg') && !$isAdmin) {
unset($result['Event']['RelatedEvent'][$key]['org']);
unset($result['Event']['RelatedEvent'][$key]['orgc']);
}
}
}
$xmlArray['response']['Event'][] = $result['Event'];
}
$xmlObject = Xml::fromArray($xmlArray, array('format' => 'tags'));
echo $xmlObject->asXML();