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

pull/3707/head
chrisr3d 2018-09-03 15:19:56 +02:00
commit d9370efcb9
42 changed files with 3648 additions and 2563 deletions

View File

@ -1,7 +1,6 @@
language: php
php:
- 5.6
- 7.0
- 7.1
- 7.2
@ -11,37 +10,30 @@ services:
- redis
sudo: required
dist: trusty
dist: bionic
group: edge
addons:
mariadb:
- '10.0'
mariadb: '10.2'
hosts:
- misp.local
- localhost
apt:
packages:
- python3-dev
- python3-pip
- python3-nose
- libxml2-dev
- libzmq3-dev
- zlib1g-dev
- apache2
- curl
- php5-mysql
- php5-dev
- php5-cli
- libapache2-mod-php5
before_install:
- git config --global user.name "TravisCI"
- export PATH="$HOME/.local/bin:$PATH"
install:
- sudo pip3 install --upgrade pip setuptools requests
- pip3 install --user --upgrade -r requirements.txt
- sudo add-apt-repository -y ppa:deadsnakes/ppa
- sudo apt-get -y update
- sudo apt-get -y install python3.6 python3-pip python3.6-dev python3-nose libxml2-dev libzmq3-dev zlib1g-dev apache2 curl php-mysql php-dev php-cli libapache2-mod-php libfuzzy-dev
- sudo apt-get -y dist-upgrade
- wget https://bootstrap.pypa.io/get-pip.py
- sudo python3.6 get-pip.py
- hash -r
- sudo pip3.6 install --upgrade pip setuptools requests
- hash -r
- sudo pip3.6 install --upgrade -r requirements.txt
- phpenv rehash
- pushd app
- composer install
@ -69,6 +61,7 @@ install:
- mysql -u misp -pblah misp < INSTALL/MYSQL.sql
# configure apache virtual hosts
- sudo chmod -R 777 `pwd`/build
- sudo mkdir -p /etc/apache2/sites-available
- sudo cp -f build/travis-ci-apache /etc/apache2/sites-available/misp.local.conf
- sudo sed -e "s?%TRAVIS_BUILD_DIR%?$(pwd)?g" --in-place /etc/apache2/sites-available/misp.local.conf
- sudo a2dissite 000-default
@ -94,6 +87,7 @@ install:
# Get authkey
- sudo usermod -a -G www-data $USER
- sudo -E su $USER -c 'app/Console/cake userInit -q | sudo tee ./key.txt'
- sudo app/Console/cake Live 1
- sudo chmod 777 ./key.txt
- sudo chmod -R 777 ./tests
- sudo chown -R www-data:www-data `pwd`
@ -116,13 +110,20 @@ script:
- ./curl_tests.sh $AUTH
- popd
- pushd PyMISP
- pip3 install --user .
- nosetests --with-coverage --cover-package=pymisp tests/test_*.py
- python3 tests/test.py
- sudo pip3.6 install nose python-dateutil
- sudo pip3.6 install git+https://github.com/kbandla/pydeep.git
- sudo pip3.6 install -e .[fileobjects,neo,openioc,virustotal]
- pushd tests
- git clone https://github.com/viper-framework/viper-test-files.git
- popd
- python3.6 tests/test.py
- python3.6 tests/test_mispevent.py
- python3.6 tests/test_offline.py
- python3.6 tests/testlive_comprehensive.py
- popd
- cp PyMISP/tests/keys.py PyMISP/examples/events/
- pushd PyMISP/examples/events/
- python3 ./create_massive_dummy_events.py -l 5 -a 30
- python3.6 ./create_massive_dummy_events.py -l 5 -a 30
- popd
- pushd app/files/feed-metadata
- jsonschema -i defaults.json schema.json

View File

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="misp-logo-bw.pdf"
viewBox="0 0 255.58075 187.30956"
height="187.30956"
width="255.58075"
xml:space="preserve"
id="svg2423"
version="1.1"
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
id="metadata2429"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs2427"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2447"><path
d="M 0,0 H 192 V 141 H 0 Z"
id="path2445"
inkscape:connector-curvature="0" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2475"><path
d="M 0,0 H 192 V 141 H 0 Z"
id="path2473"
inkscape:connector-curvature="0" /></clipPath><filter
style="color-interpolation-filters:sRGB;"
inkscape:label="Greyscale"
id="filter2551"><feColorMatrix
values="0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0 0 0 1 0 "
id="feColorMatrix2549" /></filter><filter
style="color-interpolation-filters:sRGB;"
inkscape:label="Greyscale"
id="filter2555"><feColorMatrix
values="0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0 0 0 1 0 "
id="feColorMatrix2553" /></filter><filter
style="color-interpolation-filters:sRGB;"
inkscape:label="Greyscale"
id="filter2559"><feColorMatrix
values="0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0 0 0 1 0 "
id="feColorMatrix2557" /></filter><filter
style="color-interpolation-filters:sRGB;"
inkscape:label="Greyscale"
id="filter2563"><feColorMatrix
values="0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0 0 0 1 0 "
id="feColorMatrix2561" /></filter></defs><sodipodi:namedview
inkscape:current-layer="g2431"
inkscape:window-maximized="1"
inkscape:window-y="27"
inkscape:window-x="0"
inkscape:cy="93.654778"
inkscape:cx="127.79037"
inkscape:zoom="1.2599464"
showgrid="false"
id="namedview2425"
inkscape:window-height="1025"
inkscape:window-width="1920"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff" /><g
id="g2431"
inkscape:groupmode="layer"
inkscape:label="misp"
transform="matrix(1.3333333,0,0,-1.3333333,0,187.30955)"><g
id="g2433"
style="filter:url(#filter2563);fill:#000000"><path
d="m 0,65.775 h 14.016 l 8.613,-14.129 8.617,14.129 H 45.258 V 25.572 H 31.875 v 19.93 L 22.629,31.201 H 22.398 L 13.152,45.502 V 25.572 H 0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2435"
inkscape:connector-curvature="0" /><path
d="M 51.914,65.775 H 65.352 V 25.572 H 51.914 Z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2437"
inkscape:connector-curvature="0" /></g><g
id="g2439"
style="filter:url(#filter2559);fill:#000000"><g
id="g2441"
transform="translate(0,-0.517838)"
style="fill:#000000"><g
id="g2443"
style="fill:#000000" /><g
id="g2459"
style="fill:#000000"><g
clip-path="url(#clipPath2447)"
id="g2457"
style="fill:#000000"><g
id="g2449"
style="fill:#000000" /><g
id="g2455"
style="fill:#000000"><path
d="m 68.809,32.867 7.179,8.559 c 4.364,-3.332 9.36,-4.711 14.071,-4.711 2.41,0 3.445,0.633 3.445,1.723 v 0.117 c 0,1.148 -1.262,1.777 -5.57,2.64 -9.02,1.836 -16.942,4.422 -16.942,12.922 v 0.113 c 0,7.641 5.973,13.559 17.055,13.559 7.754,0 13.5,-1.84 18.152,-5.516 l -6.547,-9.074 c -3.793,2.758 -8.328,3.961 -12.062,3.961 -2.012,0 -2.93,-0.687 -2.93,-1.664 v -0.113 c 0,-1.094 1.09,-1.781 5.34,-2.586 10.281,-1.895 17.172,-4.883 17.172,-12.981 v -0.113 c 0,-8.445 -6.949,-13.613 -17.746,-13.613 -8.156,0 -15.508,2.297 -20.617,6.777"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2451"
inkscape:connector-curvature="0" /><path
d="m 111.25,67.039 h 18.09 c 10.683,0 17.976,-4.766 17.976,-14.301 v -0.113 c 0,-9.707 -7.41,-14.875 -18.261,-14.875 h -4.367 V 26.836 H 111.25 Z M 128.309,47.34 c 3.445,0 5.742,1.551 5.742,4.422 v 0.117 c 0,2.926 -2.125,4.422 -5.688,4.422 h -3.675 V 47.34 Z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2453"
inkscape:connector-curvature="0" /></g></g></g></g></g><g
id="g2461"
style="filter:url(#filter2555);fill:#000000"><text
transform="matrix(1,0,0,-1,4.41369,4.834375)"
style="font-variant:normal;font-weight:bold;font-size:22.39999962px;font-family:'DejaVu Sans Bold';-inkscape-font-specification:DejaVuSans-Bold;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="text2465"><tspan
x="0 15.2768 31.203199 42.268799 57.456001 72.575996 83.283203 91.0784 107.2064 123.1552 138.27521 149.34081 157.024 172.97279"
y="0"
sodipodi:role="line"
id="tspan2463">Threat Sharing</tspan></text>
</g><g
id="g2467"
style="filter:url(#filter2551);fill:#000000"><g
id="g2469"
transform="translate(0,-0.517838)"
style="fill:#000000"><g
id="g2471"
style="fill:#000000" /><g
id="g2485"
style="fill:#000000"><g
clip-path="url(#clipPath2475)"
id="g2483"
style="fill:#000000"><g
id="g2481"
style="fill:#000000"><path
d="m 162.879,121.191 h -2.594 V 92.68 c 0,-4.442 -2.582,-8.457 -7.765,-8.457 h -50.77 v -1.356 c 0,-3.929 4.465,-7.887 9.051,-7.887 h 38.816 l 14.848,-8.73 -2.156,8.73 h 0.57 c 4.582,0 6.648,3.958 6.648,7.887 v 31.555 c 0,3.926 -2.066,6.769 -6.648,6.769"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2477"
inkscape:connector-curvature="0" /><path
d="M 144.941,141 H 85.977 c -5.192,0 -11.161,-4.609 -11.161,-9.051 V 96.211 c 0,-4.09 5.059,-7.043 9.911,-7.496 L 81.57,76.727 101.805,88.629 h 43.136 c 5.184,0 9.973,3.144 9.973,7.582 v 35.738 c 0,4.442 -4.789,9.051 -9.973,9.051 M 94.969,110.832 c -2.942,0 -5.324,2.387 -5.324,5.328 0,2.942 2.382,5.328 5.324,5.328 2.941,0 5.328,-2.386 5.328,-5.328 0,-2.941 -2.387,-5.328 -5.328,-5.328 m 19.898,0 c -2.941,0 -5.328,2.387 -5.328,5.328 0,2.942 2.387,5.328 5.328,5.328 2.942,0 5.324,-2.386 5.324,-5.328 0,-2.941 -2.382,-5.328 -5.324,-5.328 m 19.899,0 c -2.946,0 -5.332,2.387 -5.332,5.328 0,2.942 2.386,5.328 5.332,5.328 2.933,0 5.324,-2.386 5.324,-5.328 0,-2.941 -2.391,-5.328 -5.324,-5.328"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2479"
inkscape:connector-curvature="0" /></g></g></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 7.7 KiB

2
PyMISP

@ -1 +1 @@
Subproject commit 5d16c97178453f2624ad0ffdccb06b16578401af
Subproject commit 8b8459ce5322a205454d87f0cf95ff042c9eb53a

View File

@ -46,12 +46,13 @@ class AppController extends Controller
public $helpers = array('Utility', 'OrgImg');
private $__queryVersion = '43';
private $__queryVersion = '44';
public $pyMispVersion = '2.4.93';
public $phpmin = '5.6.5';
public $phprec = '7.0.16';
public $baseurl = '';
public $sql_dump = false;
// Used for _isAutomation(), a check that returns true if the controller & action combo matches an action that is a non-xml and non-json automation method
// This is used to allow authentication via headers for methods not covered by _isRest() - as that only checks for JSON and XML formats
@ -101,6 +102,9 @@ class AppController extends Controller
public function beforeFilter()
{
if (!empty($this->params['named']['sql'])) {
$this->sql_dump = 1;
}
// check for a supported datasource configuration
$dataSourceConfig = ConnectionManager::getDataSource('default')->config;
if (!isset($dataSourceConfig['encoding'])) {
@ -435,6 +439,14 @@ class AppController extends Controller
$this->ACL->checkAccess($this->Auth->user(), Inflector::variable($this->request->params['controller']), $this->action);
}
public function afterFilter()
{
if (Configure::read('debug') > 1 && !empty($this->sql_dump) && $this->_isRest()) {
$this->Log = ClassRegistry::init('Log');
echo json_encode($this->Log->getDataSource()->getLog(false, false), JSON_PRETTY_PRINT);
}
}
public function queryACL($debugType='findMissingFunctionNames', $content = false)
{
$this->autoRender = false;
@ -535,6 +547,69 @@ class AppController extends Controller
return $this->Auth->user('org_id');
}
protected function _getApiAuthUser(&$key, &$exception)
{
if (strlen($key) == 40) {
// check if the key is valid -> search for users based on key
$user = $this->checkAuthUser($key);
if (!$user) {
$exception = $this->RestResponse->throwException(
401,
__('This authentication key is not authorized to be used for exports. Contact your administrator.')
);
return false;
}
} else {
if (!$this->Auth->user('id')) {
$exception = $this->RestResponse->throwException(
401,
__('You have to be logged in to do that.')
);
return false;
}
$user = $this->Auth->user();
}
$key = 'json';
return $user;
}
// generic function to standardise on the collection of parameters. Accepts posted request objects, url params, named url params
protected function _harvestParameters($options, &$exception)
{
$data = array();
if (!empty($options['request']->is('post'))) {
if (empty($options['request']->data)) {
$exception = $this->RestResponse->throwException(
400,
__('Either specify the search terms in the url, or POST a json with the filter parameters.'),
'/' . $this->request->params['controller'] . '/' . $this->action
);
return false;
} else {
if (isset($options['request']->data['request'])) {
$data = $options['request']->data['request'];
} else {
$data = $options['request']->data;
}
}
}
if (!empty($options['paramArray'])) {
foreach ($options['paramArray'] as $p) {
if (
isset($options['ordered_url_params'][$p]) &&
(!in_array(strtolower($options['ordered_url_params'][$p]), array('null', '0', false, 'false', null)))
) {
$data[$p] = $options['ordered_url_params'][$p];
$data[$p] = str_replace(';', ':', $data[$p]);
}
if (isset($options['named_params'][$p])) {
$data[$p] = $options['named_params'][$p];
}
}
}
return $data;
}
// pass an action to this method for it to check the active user's access to the action
public function checkAction($action = 'perm_sync')
{

View File

@ -118,7 +118,7 @@ class AttributesController extends AppController
foreach ($attribute['AttributeTag'] as $kat => $at) {
foreach ($tags as $ktag => $tag) {
if ($tag['Tag']['id'] == $at['tag_id']) {
$attributes[$k]['AttributeTag'][$kat]['Tag'] = $tag['Tag'];
$attributes[$k]['AttributeTag'][$kat]['Tag'] = $tag['Tag'];
}
}
}
@ -775,7 +775,7 @@ class AttributesController extends AppController
// 1/ iterate over all the sources, unique
// 2/ add uniques as 'Internal reference'
// 3/ if url format -> 'link'
// else 'comment'
// else 'comment'
$references = array();
foreach ($entries as $entry) {
if (empty($entry['Source'])) {
@ -2082,183 +2082,93 @@ 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 = 'download', $value = false, $type = false, $category = false, $org = false, $tags = false, $from = false, $to = false, $last = false, $eventid = false, $withAttachments = false, $uuid = false, $publish_timestamp = false, $published = false, $timestamp = false, $enforceWarninglist = false, $to_ids = false, $deleted = false, $includeEventUuid = false, $event_timestamp = false, $threat_level_id = false)
{
if ($tags) {
$tags = str_replace(';', ':', $tags);
public function restSearch($returnFormat = 'json', $value = false, $type = false, $category = false, $org = false, $tags = false, $from = false, $to = false, $last = false, $eventid = false, $withAttachments = false, $uuid = false, $publish_timestamp = false, $published = false, $timestamp = false, $enforceWarninglist = false, $to_ids = false, $deleted = false, $includeEventUuid = false, $event_timestamp = false, $threat_level_id = false) {
$paramArray = array('value' , 'type', 'category', 'org', 'tags', 'from', 'to', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'event_timestamp', 'threat_level_id');
$filterData = array(
'request' => $this->request,
'named_params' => $this->params['named'],
'paramArray' => $paramArray,
'ordered_url_params' => compact($paramArray)
);
$validFormats = array(
'openioc' => array('xml', 'OpeniocExport'),
'json' => array('json', 'JsonExport'),
'xml' => array('xml', 'XmlExport'),
'suricata' => array('txt', 'NidsSuricataExport'),
'snort' => array('txt', 'NidsSnortExport'),
'text' => array('txt', 'TextExport')
);
$exception = false;
$filters = $this->_harvestParameters($filterData, $exception);
unset($filterData);
if ($filters === false) {
return $exception;
}
$simpleFalse = array('value' , 'type', 'category', 'org', 'tags', 'from', 'to', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'event_timestamp', 'threat_level_id');
foreach ($simpleFalse as $sF) {
if (${$sF} === 'null' || ${$sF} == '0' || ${$sF} === false || strtolower(${$sF}) === 'false') {
${$sF} = false;
}
$list = array();
$user = $this->_getApiAuthUser($returnFormat, $exception);
if ($user === false) {
return $exception;
}
if ($key != null && strlen($key) == 40) {
$user = $this->checkAuthUser($key);
if (!$user) {
throw new UnauthorizedException(__('This authentication key is not authorized to be used for exports. Contact your administrator.'));
}
} else {
$key = strtolower($key);
if (!$this->Auth->user()) {
throw new UnauthorizedException(__('You are not authorized. Please send the Authorization header with your auth key along with an Accept header for application/xml.'));
}
if (isset($filters['returnFormat'])) {
$returnFormat = $filters['returnFormat'];
}
// request handler for POSTed queries. If the request is a post, the parameters (apart from the key) will be ignored and replaced by the terms defined in the posted json or xml object.
// The correct format for both is a "request" root element, as shown by the examples below:
// For Json: {"request":{"value": "7.7.7.7&&1.1.1.1","type":"ip-src"}}
// For XML: <request><value>7.7.7.7&amp;&amp;1.1.1.1</value><type>ip-src</type></request>
// the response type is used to determine the parsing method (xml/json)
if ($this->request->is('post')) {
if ($this->response->type() === 'application/json') {
if ($key == 'xml') {
throw new MethodNotAllowedException(__('Content type and parameter mismatch. Expecting JSON.'));
}
$data = $this->request->input('json_decode', true);
} elseif ($this->response->type() === 'application/xml' && !empty($this->request->data)) {
if ($key == 'json') {
throw new MethodNotAllowedException(__('Content type and parameter mismatch. Expecting XML.'));
}
$data = $this->request->data;
} else {
throw new BadRequestException(__('Either specify the search terms in the url, or POST a json array / xml (with the root element being "request" and specify the correct accept and content type headers).'));
}
if (!isset($data['request'])) {
$data['request'] = $data;
}
$paramArray = array('value', 'type', 'category', 'org', 'tags', 'from', 'to', 'last', 'eventid', 'uuid', 'published', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'event_timestamp', 'threat_level_id');
foreach ($paramArray as $p) {
if (isset($data['request'][$p])) {
${$p} = $data['request'][$p];
} else {
${$p} = null;
}
}
}
$simpleFalse = array('value' , 'type', 'category', 'org', 'tags', 'from', 'to', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'event_timestamp', 'threat_level_id');
foreach ($simpleFalse as $sF) {
if (!is_array(${$sF}) && (${$sF} === 'null' || ${$sF} == '0' || ${$sF} === false || strtolower(${$sF}) === 'false')) {
${$sF} = 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);
}
$conditions['AND'] = array();
$subcondition = array();
$this->loadModel('Attribute');
// add the values as specified in the 2nd parameter to the conditions
$parameters = array('value', 'type', 'category', 'org', 'eventid', 'uuid');
foreach ($parameters as $k => $param) {
if (isset(${$parameters[$k]}) && ${$parameters[$k]} !== false) {
$conditions = $this->Attribute->Event->setSimpleConditions($parameters[$k], ${$parameters[$k]}, $conditions);
}
}
// If we sent any tags along, load the associated tag names for each attribute
if ($tags) {
$conditions = $this->Attribute->setTagConditions($tags, $conditions, 'attribute');
}
if ($from) {
$conditions['AND'][] = array('Event.date >=' => $from);
}
if ($to) {
$conditions['AND'][] = array('Event.date <=' => $to);
}
if ($publish_timestamp) {
$conditions = $this->Attribute->setTimestampConditions($publish_timestamp, $conditions, 'Event.publish_timestamp');
}
if ($last) {
$conditions['AND'][] = array('Event.publish_timestamp >=' => $last);
}
if ($published) {
$conditions['AND'][] = array('Event.published' => $published);
}
if ($timestamp) {
$conditions = $this->Attribute->setTimestampConditions($timestamp, $conditions, 'Attribute.timestamp');
}
if ($event_timestamp) {
$conditions = $this->Attribute->setTimestampConditions($event_timestamp, $conditions, 'Event.timestamp');
}
if ($threat_level_id) {
if (!is_array($threat_level_id)) {
$threat_level_id = array($threat_level_id);
}
$threat_level_lookup = array('high' => 1, 'medium' => 2, 'low' => 3, 'undefined' => 4);
foreach ($threat_level_id as $tldk => $tld) {
if (!is_numeric($tld)) {
if (isset($threat_level_lookup[strtolower($tld)])) {
$threat_level_id[$tldk] = $threat_level_lookup[strtolower($tld)];
}
}
}
$conditions['AND'][] = array('Event.threat_level_id' => $threat_level_id);
}
if ($to_ids) {
$conditions = $this->Attribute->setToIDSConditions($to_ids, $conditions);
}
// 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?
$conditions = $this->Attribute->buildFilterConditions($this->Auth->user(), $filters);
$params = array(
'conditions' => $conditions,
'fields' => array('Attribute.*', 'Event.org_id', 'Event.distribution'),
'withAttachments' => $withAttachments,
'enforceWarninglist' => $enforceWarninglist,
'withAttachments' => !empty($filters['withAttachments']) ? $filters['withAttachments'] : 0,
'enforceWarninglist' => !empty($filters['enforceWarninglist']) ? $filters['enforceWarninglist'] : 0,
'includeAllTags' => true,
'flatten' => 1,
'includeEventUuid' => $includeEventUuid
'includeEventUuid' => !empty($filters['includeEventUuid']) ? $filters['includeEventUuid'] : 0,
);
if ($deleted) {
if (!empty($filtes['deleted'])) {
$params['deleted'] = 1;
if ($deleted === 'only') {
if ($params['deleted'] === 'only') {
$params['conditions']['AND'][] = array('Attribute.deleted' => 1);
$params['conditions']['AND'][] = array('Object.deleted' => 1);
}
}
$results = $this->Attribute->fetchAttributes($this->Auth->user(), $params);
$this->loadModel('Whitelist');
$results = $this->Whitelist->removeWhitelistedFromArray($results, true);
if ($key == 'openioc') {
App::uses('IOCExportTool', 'Tools');
$this->IOCExport = new IOCExportTool();
$results = $this->IOCExport->buildAll($this->Auth->user(), $results, 'attribute');
} else {
if (!empty($results)) {
$results = array('response' => array('Attribute' => $results));
foreach ($results['response']['Attribute'] as $k => $v) {
if (isset($results['response']['Attribute'][$k]['AttributeTag'])) {
foreach ($results['response']['Attribute'][$k]['AttributeTag'] as $tk => $tag) {
$results['response']['Attribute'][$k]['Attribute']['Tag'][$tk] = $tag['Tag'];
}
}
$results['response']['Attribute'][$k] = $results['response']['Attribute'][$k]['Attribute'];
unset(
$results['response']['Attribute'][$k]['value1'],
$results['response']['Attribute'][$k]['value2']
);
}
} else {
$results = array('response' => array());
}
}
$responseType = $this->response->type();
if ($key == 'openioc') {
$responseType = 'openioc';
}
return $this->RestResponse->viewData($results, $responseType);
App::uses($validFormats[$returnFormat][1], 'Export');
$exportTool = new $validFormats[$returnFormat][1]();
$exportToolParams = array(
'user' => $this->Auth->user(),
'params' => $params,
'returnFormat' => $returnFormat,
'scope' => 'Attribute'
);
if (!empty($exportTool->additional_params)) {
$params = array_merge($params, $exportTool->additional_params);
}
$final = '';
$final .= $exportTool->header($exportToolParams);
$continue = false;
if (empty($params['limit'])) {
$params['limit'] = 10000;
$continue = true;
$params['page'] = 1;
}
$this->loadModel('Whitelist');
while ($continue) {
$results = $this->Attribute->fetchAttributes($this->Auth->user(), $params, $continue);
$params['page'] += 1;
$results = $this->Whitelist->removeWhitelistedFromArray($results, true);
$results = array_values($results);
$i = 0;
foreach ($results as $attribute) {
$temp = $exportTool->handler($attribute, $exportToolParams);
if ($temp !== '') {
$final .= $temp;
if ($i != count($results) -1) {
$final .= $exportTool->separator($exportToolParams);
}
}
$i++;
}
}
$final .= $exportTool->footer($exportToolParams);
$responseType = $validFormats[$returnFormat][0];
return $this->RestResponse->viewData($final, $responseType, false, true);
}
// 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.
@ -2310,7 +2220,7 @@ class AttributesController extends AppController
throw new UnauthorizedException(__('You don\'t have access to that event.'));
}
}
$this->response->type('xml'); // set the content type
$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!
@ -2445,7 +2355,7 @@ class AttributesController extends AppController
throw new UnauthorizedException(__('You have to be logged in to do that.'));
}
}
$this->response->type('txt'); // set the content type
$this->response->type('txt'); // set the content type
$this->header('Content-Disposition: download; filename="misp.' . (is_array($type) ? 'multi' : $type) . '.txt"');
$this->layout = 'text/default';
$attributes = $this->Attribute->text($this->Auth->user(), $type, $tags, $eventId, $allowNonIDS, $from, $to, $last, $enforceWarninglist, $allowNotPublished);
@ -2539,7 +2449,7 @@ class AttributesController extends AppController
foreach ($eventIds as $k => $eventId) {
$values = array_merge_recursive($values, $this->Attribute->rpz($this->Auth->user(), $tags, $eventId, $from, $to, $enforceWarninglist));
}
$this->response->type('txt'); // set the content type
$this->response->type('txt'); // set the content type
$file = '';
if ($tags) {
$file = 'filtered.';

View File

@ -312,6 +312,7 @@ class ACLComponent extends Component
'edit' => array(),
'fetchServersForSG' => array('*'),
'filterEventIndex' => array(),
'getApiInfo' => array('*'),
'getGit' => array(),
'getInstanceUUID' => array('perm_sync'),
'getPyMISPVersion' => array('*'),
@ -570,7 +571,7 @@ class ACLComponent extends Component
$fileContents = preg_replace('/\/\*[^\*]+?\*\//', '', $fileContents);
preg_match_all($functionFinder, $fileContents, $functionArray);
foreach ($functionArray[1] as $function) {
if (substr($function, 0, 1) !== '_' && $function !== 'beforeFilter') {
if (substr($function, 0, 1) !== '_' && $function !== 'beforeFilter' && $function !== 'afterFilter') {
$results[$controllerName][] = $function;
}
}

View File

@ -190,6 +190,35 @@ class RestResponseComponent extends Component
)
);
// use a relative path to check if the current api has a description
public function getApiInfo($relative_path)
{
$relative_path = trim($relative_path, '/');
$relative_path = explode('/', $relative_path);
$admin = false;
if (count($relative_path) >= 2) {
if ($relative_path[0] == 'admin') {
if (count($relative_path) < 3) {
return '[]';
}
$admin = true;
$relative_path = array_slice($relative_path, 1);
}
$relative_path[0] = Inflector::camelize(Inflector::singularize($relative_path[0]));
if ($admin) {
$relative_path[1] = 'admin_' . $relative_path[1];
}
if (isset($this->__descriptions[$relative_path[0]][$relative_path[1]])) {
$temp = $this->__descriptions[$relative_path[0]][$relative_path[1]];
} else {
$temp = array();
}
if (empty($temp)) return '[]';
return json_encode(array('api_info' => $temp));
}
return '[]';
}
public function saveFailResponse($controller, $action, $id = false, $validationErrors, $format = false)
{
$this->autoRender = false;
@ -278,8 +307,13 @@ class RestResponseComponent extends Component
return $this->__sendResponse($data, 200, $format, $raw, $download);
}
public function throwException($code, $message, $format, $raw)
public function throwException($code, $message, $url = '', $format = false, $raw = false)
{
$message = array(
'name' => $message,
'message' => $message,
'url' => $url
);
return $this->__sendResponse($message, $code, $format, $raw);
}

View File

@ -2679,56 +2679,26 @@ class EventsController extends AppController
public function csv($key, $eventid = false, $ignore = false, $tags = false, $category = false, $type = false, $includeContext = false, $from = false, $to = false, $last = false, $headerless = false, $enforceWarninglist = false, $value = false, $timestamp = false)
{
$paramArray = array('eventid', 'ignore', 'tags', 'category', 'type', 'includeContext', 'from', 'to', 'last', 'headerless', 'enforceWarninglist', 'value', 'timestamp');
if ($this->request->is('post')) {
if (empty($this->request->data)) {
return $this->RestResponse->throwException(400, __('Either specify the search terms in the url, or POST a json or xml with the filter parameters.'), 'csv', true);
} else {
$data = $this->request->data;
}
if (!isset($data['request'])) {
$data = array('request' => $data);
}
foreach ($paramArray as $p) {
if (isset($data['request'][$p])) {
${$p} = $data['request'][$p];
}
}
}
foreach ($paramArray as $p) {
if (!is_array(${$p}) && (${$p} === 'null' || ${$p} == '0' || ${$p} === false || strtolower(${$p}) === 'false')) {
${$p} = false;
}
}
$exportType = $eventid;
if ($from) {
$from = $this->Event->dateFieldCheck($from);
}
if ($to) {
$to = $this->Event->dateFieldCheck($to);
}
if ($tags) {
$tags = str_replace(';', ':', $tags);
}
if ($last) {
$last = $this->Event->resolveTimeDelta($last);
$filterData = array(
'request' => $this->request,
'named_params' => $this->params['named'],
'paramArray' => $paramArray,
'ordered_url_params' => compact($paramArray)
);
$exception = false;
$filters = $this->_harvestParameters($filterData, $exception);
if ($filters === false) {
return $exception;
}
$list = array();
if ($key != 'download') {
// check if the key is valid -> search for users based on key
$user = $this->checkAuthUser($key);
if (!$user) {
return $this->RestResponse->throwException(401, __('This authentication key is not authorized to be used for exports. Contact your administrator.'), 'csv', true);
}
} else {
if (!$this->Auth->user('id')) {
return $this->RestResponse->throwException(401, __('You have to be logged in to do that.'), 'csv', true);
}
$user = $this->Auth->user();
$user = $this->_getApiAuthUser($key, $exception);
if ($user === false) {
return $exception;
}
// if it's a search, grab the attributeIDList from the session and get the IDs from it. Use those as the condition
// We don't need to look out for permissions since that's filtered by the search itself
// We just want all the attributes found by the search
if ($eventid === 'search') {
if (!empty($filters['eventid']) && $filters['eventid'] === 'search') {
$ioc = $this->Session->read('paginate_conditions_ioc');
$paginateConditions = $this->Session->read('paginate_conditions');
unset($paginateConditions['contain']['Event']['Orgc']);
@ -2752,31 +2722,10 @@ class EventsController extends AppController
);
$list[] = $attribute['Attribute']['id'];
}
$events = array($eventid);
} elseif ($eventid === false) {
$events = $this->Event->fetchEventIds($this->Auth->user(), $from, $to, $last, true);
if (empty($events)) {
$events = array(0 => -1);
}
} else {
$events = array($eventid);
} elseif (!empty($filters['eventid']) && $filters['eventid'] !== 'all') {
$events = $filters['eventid'];
}
$final = array();
$this->loadModel('Whitelist');
if ($tags) {
$args = $this->Event->Attribute->dissectArgs($tags);
$tagArray = $this->Event->EventTag->Tag->fetchEventTagIds($args[0], $args[1]);
if (!empty($tagArray[0])) {
$events = array_intersect($events, $tagArray[0]);
}
if (!empty($tagArray[1])) {
foreach ($events as $k => $eventid) {
if (in_array($eventid, $tagArray[1])) {
unset($events[$k]);
}
}
}
}
$requested_attributes = array('uuid', 'event_id', 'category', 'type',
'value', 'comment', 'to_ids', 'timestamp', 'object_relation');
$requested_obj_attributes = array('uuid', 'name', 'meta-category');
@ -2801,65 +2750,50 @@ class EventsController extends AppController
if (isset($data['request']['obj_attributes'])) {
$requested_obj_attributes = $data['request']['obj_attributes'];
}
if (isset($events)) {
$events = array_chunk($events, 100);
foreach ($events as $k => $eventid) {
$attributes = $this->Event->csv($user, $eventid, $ignore, $list, false, $category, $type, $includeContext, false, false, false, $enforceWarninglist, $value, $timestamp);
$attributes = $this->Whitelist->removeWhitelistedFromArray($attributes, true);
foreach ($attributes as $attribute) {
$line1 = '';
$line2 = '';
foreach ($requested_attributes as $requested_attribute) {
$line1 .= $attribute['Attribute'][$requested_attribute] . ',';
}
$line1 = rtrim($line1, ",");
foreach ($requested_obj_attributes as $requested_obj_attribute) {
$line2 .= $attribute['Object'][$requested_obj_attribute] . ',';
}
$line2 = rtrim($line2, ",");
$line = $line1 . ',' . $line2;
$line = rtrim($line, ",");
if ($includeContext) {
foreach ($this->Event->csv_event_context_fields_to_fetch as $header => $field) {
if ($field['object']) {
$line .= ',' . $attribute['Event'][$field['object']][$field['var']];
} else {
$line .= ',' . str_replace(array("\n","\t","\r"), " ", $attribute['Event'][$field['var']]);
}
}
}
$final[] = $line;
}
$possibleParams = array(
'ignore', 'list', 'category', 'type', 'includeContext',
'enforceWarninglist', 'value', 'timestamp', 'tags',
'last', 'from', 'to'
);
$params = array();
if (!empty($events)) {
$filters['eventid'] = $events;
}
foreach ($possibleParams as $possibleParam) {
if (isset($filters[$possibleParam])) {
$params[$possibleParam] = $filters[$possibleParam];
}
}
$params['limit'] = 1000;
$params['page'] = 1;
$i = 0;
$continue = true;
$options = array(
'requested_obj_attributes' => $requested_obj_attributes,
'requested_attributes' => $requested_attributes,
'includeContext' => $includeContext
);
App::uses('CsvExport', 'Export');
$export = new CsvExport();
$final = $export->header($options);
while ($continue) {
$attributes = $this->Event->csv($user, $params, false, $continue);
$params['page'] += 1;
$final .= $export->handler($attributes, $final, $options);
$final .= $export->separator($attributes, $final);
}
$export->footer();
$this->response->type('csv'); // set the content type
if (!$exportType) {
$filename = "misp.all_attributes.csv";
} elseif ($exportType === 'search') {
if (empty($filters['eventid'])) {
$filename = "misp.filtered_attributes.csv";
} elseif ($filters['eventid'] === 'search') {
$filename = "misp.search_result.csv";
} else {
$filename = "misp.event_" . $exportType . ".csv";
}
$this->layout = 'text/default';
if (!empty($requested_obj_attributes)) {
array_walk($requested_obj_attributes, function (&$value, $key) {
$value = 'object-'.$value;
});
}
$headers = array_merge($requested_attributes, $requested_obj_attributes);
if ($includeContext) {
$headers = array_merge($headers, array_keys($this->Event->csv_event_context_fields_to_fetch));
}
foreach ($headers as $k => $v) {
$headers[$k] = str_replace('-', '_', $v);
if ($v == 'timestamp') {
$headers[$k] = 'date';
if (is_array($filters['eventid'])) {
$filters['eventid'] = 'list';
}
$filename = "misp.event_" . $filters['eventid'] . ".csv";
}
$headers = implode(',', $headers);
$final = array_merge(array($headers), $final);
$final = implode(PHP_EOL, $final);
$final .= PHP_EOL;
return $this->RestResponse->viewData($final, 'csv', false, true, $filename);
}
@ -3072,168 +3006,38 @@ class EventsController extends AppController
// 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 = 'download', $value = false, $type = false, $category = false, $org = false, $tags = false, $searchall = false, $from = false, $to = false, $last = false, $eventid = false, $withAttachments = false, $metadata = false, $uuid = false, $publish_timestamp = false, $timestamp = false, $published = false, $enforceWarninglist = false, $sgReferenceOnly = false)
public function restSearch($returnFormat = 'json', $value = false, $type = false, $category = false, $org = false, $tags = false, $searchall = false, $from = false, $to = false, $last = false, $eventid = false, $withAttachments = false, $metadata = false, $uuid = false, $publish_timestamp = false, $timestamp = false, $published = false, $enforceWarninglist = false, $sgReferenceOnly = false)
{
if ($key != null && strlen($key) == 40) {
if (!$this->checkAuthUser($key)) {
throw new UnauthorizedException(__('This authentication key is not authorized to be used for exports. Contact your administrator.'));
}
} else {
$key = strtolower($key);
if (!$this->Auth->user()) {
throw new UnauthorizedException(__('You are not authorized. Please send the Authorization header with your auth key along with an Accept header for application/xml.'));
}
$paramArray = array('value', 'type', 'category', 'org', 'tag', 'tags', 'searchall', 'from', 'to', 'last', 'eventid', 'withAttachments', 'metadata', 'uuid', 'published', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'sgReferenceOnly');
$filterData = array(
'request' => $this->request,
'named_params' => $this->params['named'],
'paramArray' => $paramArray,
'ordered_url_params' => compact($paramArray)
);
$exception = false;
$filters = $this->_harvestParameters($filterData, $exception);
unset($filterData);
if ($filters === false) {
return $exception;
}
if (!is_array($value) && $value !== false) {
$value = str_replace('|', '/', $value);
$list = array();
$user = $this->_getApiAuthUser($returnFormat, $exception);
if ($user === false) {
return $exception;
}
// request handler for POSTed queries. If the request is a post, the parameters (apart from the key) will be ignored and replaced by the terms defined in the posted json or xml object.
// The correct format for both is a "request" root element, as shown by the examples below:
// For Json: {"request":{"value": "7.7.7.7&&1.1.1.1","type":"ip-src"}}
// For XML: <request><value>7.7.7.7&amp;&amp;1.1.1.1</value><type>ip-src</type></request>
// the response type is used to determine the parsing method (xml/json)
if ($this->request->is('post')) {
if ($this->response->type() === 'application/json') {
$data = $this->request->input('json_decode', true);
} elseif ($this->response->type() === 'application/xml') {
$data = $this->request->data;
} else {
throw new BadRequestException(__('Either specify the search terms in the url, or POST a json array / xml (with the root element being "request" and specify the correct headers based on content type).'));
}
if (!isset($data['request'])) {
$data['request'] = $data;
}
$paramArray = array('value', 'type', 'category', 'org', 'tag', 'tags', 'searchall', 'from', 'to', 'last', 'eventid', 'withAttachments', 'metadata', 'uuid', 'published', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'sgReferenceOnly');
foreach ($paramArray as $p) {
if (isset($data['request'][$p])) {
${$p} = $data['request'][$p];
} else {
${$p} = null;
}
}
if (isset($filters['returnFormat'])) {
$returnFormat = $filters['returnFormat'];
}
$simpleFalse = array('value' , 'type', 'category', 'org', 'tags', 'searchall', 'from', 'to', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'sgReferenceOnly');
foreach ($simpleFalse as $sF) {
if (!is_array(${$sF}) && (${$sF} === 'null' || ${$sF} == '0' || ${$sF} === false || strtolower(${$sF}) === 'false')) {
${$sF} = false;
}
}
if ($from) {
$from = $this->Event->dateFieldCheck($from);
}
if ($to) {
$to = $this->Event->dateFieldCheck($to);
}
if (!empty($tag) && !$tags) {
$tags = $tag;
}
if ($tags) {
$tags = str_replace(';', ':', $tags);
}
if ($last) {
$last = $this->Event->resolveTimeDelta($last);
}
if ($searchall === 'true') {
$searchall = "1";
}
$conditions['AND'] = array();
$subcondition = array();
$this->loadModel('Attribute');
// add the values as specified in the 2nd parameter to the conditions
if (isset($searchall) && ($searchall == 1 || $searchall === true || $searchall == 'true')) {
$eventIds = $this->__quickFilter($value);
} else {
$parameters = array('value', 'type', 'category', 'org', 'uuid', 'eventid');
$attributeLevelFilters = array('value', 'type', 'category', 'uuid');
$preFilterLevel = 'event';
foreach ($parameters as $k => $param) {
if (${$parameters[$k]} !== null && ${$parameters[$k]} !== false) {
if (in_array($param, $attributeLevelFilters)) {
$preFilterLevel = 'attribute';
}
if ($param == 'eventid') {
$restrictScopeToEvents = true;
}
$conditions = $this->Event->setSimpleConditions($parameters[$k], ${$parameters[$k]}, $conditions, !empty($restrictScopeToEvents));
}
}
// If we sent any tags along, load the associated tag names for each attribute
if ($tags) {
$conditions = $this->Event->Attribute->setTagConditions($tags, $conditions);
}
$blockedAttributeTags = array();
if (!empty($tags)) {
if (!is_array($tags)) {
$tags = explode('&&', $tags);
}
foreach ($tags as $tag) {
if ($tag[0] == '!') {
$blockedAttributeTags[] = ltrim($tag, '!');
}
}
$preFilterLevel = 'attribute';
}
if ($from) {
$conditions['AND'][] = array('Event.date >=' => $from);
}
if ($to) {
$conditions['AND'][] = array('Event.date <=' => $to);
}
if ($publish_timestamp) {
$conditions = $this->Event->Attribute->setTimestampConditions($publish_timestamp, $conditions, 'Event.publish_timestamp');
}
if ($timestamp) {
$conditions = $this->Event->Attribute->setTimestampConditions($timestamp, $conditions, 'Event.timestamp');
}
if ($last) {
$conditions['AND'][] = array('Event.publish_timestamp >=' => $last);
}
if ($published !== null && $published !== false) {
$conditions['AND'][] = array('Event.published' => $published);
}
if ($preFilterLevel == 'event') {
$params = array(
'conditions' => $conditions
);
$eventIds = $this->Event->fetchSimpleEventIds($this->Auth->user(), $params);
} else {
$params = array(
'conditions' => $conditions,
'fields' => array('DISTINCT(Attribute.event_id)'),
'contain' => array(),
'recursive' => -1,
'list' => true,
'event_ids' => true,
'flatten' => 1
);
$attributes = $this->Event->Attribute->fetchAttributes($this->Auth->user(), $params);
$eventIds = array();
if (!empty($attributes)) {
$eventIds = array_values($attributes);
}
if (is_array($eventid)) {
foreach ($eventid as $temp_id) {
if (!in_array($temp_id, $eventIds)) {
$eventIds[] = $temp_id;
}
}
} else {
if ($eventid && !in_array($eventid, $eventIds)) {
$eventIds[] = $eventid;
}
}
unset($attributes);
}
}
$this->loadModel('Whitelist');
$responseType = 'xml';
$eventid = $this->Event->filterEventIds($user, $filters);
$responseType = 'json';
$converters = array(
'xml' => 'XMLConverterTool',
'json' => 'JSONConverterTool',
'openioc' => 'IOCExportTool'
);
if (in_array($key, array('json', 'xml', 'openioc'))) {
$responseType = $key;
if (in_array($returnFormat, array('json', 'xml', 'openioc'))) {
$responseType = $returnFormat;
} elseif (((isset($this->request->params['ext']) && $this->request->params['ext'] == 'xml')) || $this->response->type() == 'application/xml') {
$responseType = 'xml';
} else {
@ -3242,22 +3046,20 @@ class EventsController extends AppController
App::uses($converters[$responseType], 'Tools');
$converter = new $converters[$responseType]();
$final = $converter->generateTop($this->Auth->user());
$eventCount = count($eventIds);
$eventCount = count($eventid);
$i = 0;
foreach ($eventIds as $k => $currentEventId) {
foreach ($eventid as $k => $currentEventId) {
$filters['eventid'] = $currentEventId;
if (!empty($filters['tags']['NOT'])) {
$filters['blockedAttributeTags'] = $filters['tags']['NOT'];
}
$result = $this->Event->fetchEvent(
$this->Auth->user(),
array(
'blockedAttributeTags' => $blockedAttributeTags,
'eventid' => $currentEventId,
'includeAttachments' => $withAttachments,
'metadata' => $metadata,
'enforceWarninglist' => $enforceWarninglist,
'sgReferenceOnly' => $sgReferenceOnly
),
$filters,
true
);
if (!empty($result)) {
$this->loadModel('Whitelist');
$result = $this->Whitelist->removeWhitelistedFromArray($result, false);
if ($i != 0) {
$final .= ',' . PHP_EOL;
@ -3271,7 +3073,7 @@ class EventsController extends AppController
}
$final .= $converter->generateBottom($responseType, $final);
$extension = $responseType;
if ($key == 'openioc') {
if ($returnFormat == 'openioc') {
$extension = '.ioc';
}
if (isset($eventid) && $eventid) {

View File

@ -31,7 +31,7 @@ class ServersController extends AppController
public function beforeFilter()
{
parent::beforeFilter();
$this->Security->unlockedActions[] = 'getApiInfo';
// permit reuse of CSRF tokens on some pages.
switch ($this->request->params['action']) {
case 'push':
@ -1611,7 +1611,8 @@ class ServersController extends AppController
return $this->RestResponse->viewData(array('uuid' => Configure::read('MISP.uuid')), $this->response->type());
}
public function rest() {
public function rest()
{
if ($this->request->is('post')) {
$request = $this->request->data;
if (!empty($request['Server'])) {
@ -1631,21 +1632,19 @@ class ServersController extends AppController
$this->set('header', $header);
}
private function __doRestQuery($request) {
private function __doRestQuery($request)
{
App::uses('SyncTool', 'Tools');
$params = array(
);
$params = array();
if (!empty($request['url'])) {
$path = parse_url($request['url'], PHP_URL_PATH);
$query = parse_url($request['url'], PHP_URL_QUERY);
if (!empty($query)) {
$path .= '?' . $query;
}
$path = preg_replace('#^(://|[^/?])+#', '', $request['url']);
$url = Configure::read('MISP.baseurl') . '/' . $path;
} else {
throw new InvalidArgumentException('Url not set.');
}
if (!empty($request['skip_ssl_validation'])) {
$params['ssl_verify_peer'] = false;
}
App::uses('HttpSocket', 'Network/Http');
$HttpSocket = new HttpSocket($params);
$view_data = array();
@ -1667,7 +1666,7 @@ class ServersController extends AppController
$request['method'] === 'GET'
) {
$response = $HttpSocket->get($url, false, array('header' => $request['header']));
} else if (
} elseif (
!empty($request['method']) &&
$request['method'] === 'POST' &&
!empty($request['body'])
@ -1691,4 +1690,21 @@ class ServersController extends AppController
}
return $view_data;
}
public function getApiInfo() {
$relative_path = $this->request->data['url'];
$result = $this->RestResponse->getApiInfo($relative_path);
if ($this->_isRest()) {
return $result;
} else {
$result = json_decode($result, true);
if (empty($result)) {
return $this->RestResponse->viewData('&nbsp;', $this->response->type());
}
$this->layout = false;
$this->autoRender = false;
$this->set('api_info', $result);
$this->render('ajax/get_api_info');
}
}
}

View File

@ -750,7 +750,6 @@ class UsersController extends AppController
array_push($fields, $field);
}
}
// TODO Audit, __extralog, fields get orig
$fieldsOldValues = array();
foreach ($fields as $field) {
if ($field == 'enable_password') {
@ -762,7 +761,6 @@ class UsersController extends AppController
array_push($fieldsOldValues, $this->User->field('password'));
}
}
// TODO Audit, __extralog, fields get orig END
if (
isset($this->request->data['User']['enable_password']) && $this->request->data['User']['enable_password'] != '0' &&
isset($this->request->data['User']['password']) && "" != $this->request->data['User']['password']
@ -785,7 +783,6 @@ class UsersController extends AppController
}
}
if ($this->User->save($this->request->data, true, $fields)) {
// TODO Audit, __extralog, fields compare
// newValues to array
$fieldsNewValues = array();
foreach ($fields as $field) {
@ -822,8 +819,7 @@ class UsersController extends AppController
$c++;
}
$fieldsResultStr = substr($fieldsResultStr, 2);
$this->__extralog("edit", "user", $fieldsResultStr); // TODO Audit, check: modify User
// TODO Audit, __extralog, fields compare END
$this->__extralog("edit", "user", $fieldsResultStr);
if ($this->_isRest()) {
$user = $this->User->find('first', array(
'conditions' => array('User.id' => $this->User->id),
@ -853,7 +849,7 @@ class UsersController extends AppController
$this->redirect(array('controller' => 'users', 'action' => 'index', 'admin' => true));
}
$this->User->set('password', '');
$this->request->data = $this->User->data; // TODO CHECK
$this->request->data = $this->User->data;
}
if ($this->_isSiteAdmin()) {
$orgs = $this->User->Organisation->find('list', array(
@ -964,7 +960,7 @@ class UsersController extends AppController
}
}
if ($this->Auth->login()) {
$this->__extralog("login"); // TODO Audit, __extralog, check: customLog i.s.o. __extralog, no auth user?: $this->User->customLog('login', $this->Auth->user('id'), array('title' => '','user_id' => $this->Auth->user('id'),'email' => $this->Auth->user('email'),'org' => 'IN2'));
$this->__extralog("login");
$this->User->Behaviors->disable('SysLogLogable.SysLogLogable');
$this->User->id = $this->Auth->user('id');
$user = $this->User->find('first', array(
@ -1074,8 +1070,8 @@ class UsersController extends AppController
public function logout()
{
if ($this->Session->check('Auth.User')) { // TODO session, user is logged in, so ..
$this->__extralog("logout"); // TODO Audit, __extralog, check: customLog i.s.o. __extralog, $this->User->customLog('logout', $this->Auth->user('id'), array());
if ($this->Session->check('Auth.User')) {
$this->__extralog("logout");
}
$this->Flash->info(__('Good-Bye'));
$user = $this->User->find('first', array(
@ -1245,7 +1241,7 @@ class UsersController extends AppController
}
private function __extralog($action = null, $description = null, $fieldsResult = null)
{ // TODO move audit to AuditsController?
{
// new data
$model = 'User';
$modelId = $this->Auth->user('id');

View File

@ -0,0 +1,79 @@
<?php
class CsvExport
{
public $csv_event_context_fields_to_fetch = array(
'event_info' => array('object' => false, 'var' => 'info'),
'event_member_org' => array('object' => 'Org', 'var' => 'name'),
'event_source_org' => array('object' => 'Orgc', 'var' => 'name'),
'event_distribution' => array('object' => false, 'var' => 'distribution'),
'event_threat_level_id' => array('object' => 'ThreatLevel', 'var' => 'name'),
'event_analysis' => array('object' => false, 'var' => 'analysis'),
'event_date' => array('object' => false, 'var' => 'date'),
'event_tag' => array('object' => 'Tag', 'var' => 'name')
);
public function handler($attributes, $final, $options = array())
{
$result = array();
foreach ($attributes as $attribute) {
$line1 = '';
$line2 = '';
foreach ($options['requested_attributes'] as $requested_attribute) {
$line1 .= $attribute['Attribute'][$requested_attribute] . ',';
}
$line1 = rtrim($line1, ",");
foreach ($options['requested_obj_attributes'] as $requested_obj_attribute) {
$line2 .= $attribute['Object'][$requested_obj_attribute] . ',';
}
$line2 = rtrim($line2, ",");
$line = $line1 . ',' . $line2;
$line = rtrim($line, ",");
if (!empty($options['includeContext'])) {
foreach ($this->Event->csv_event_context_fields_to_fetch as $header => $field) {
if ($field['object']) {
$line .= ',' . $attribute['Event'][$field['object']][$field['var']];
} else {
$line .= ',' . str_replace(array("\n","\t","\r"), " ", $attribute['Event'][$field['var']]);
}
}
}
$result[] = $line;
}
$result = implode(PHP_EOL, $result);
return $result;
}
public function header($options = array())
{
if (!empty($options['requested_obj_attributes'])) {
array_walk($options['requested_obj_attributes'], function (&$value, $key) {
$value = 'object-'.$value;
});
}
$headers = array_merge($options['requested_attributes'], $options['requested_obj_attributes']);
if (!empty($options['includeContext'])) {
$headers = array_merge($headers, array_keys($this->csv_event_context_fields_to_fetch));
}
foreach ($headers as $k => $v) {
$headers[$k] = str_replace('-', '_', $v);
if ($v == 'timestamp') {
$headers[$k] = 'date';
}
}
$headers = implode(',', $headers) . PHP_EOL;
return $headers;
}
public function footer()
{
return PHP_EOL;
}
public function separator()
{
return PHP_EOL;
}
}

View File

@ -0,0 +1,48 @@
<?php
class JsonExport
{
public function handler($data, $options = array())
{
if ($options['scope'] === 'Attribute') {
return $this->__attributeHandler($data, $options);
} else {
return $this->__eventHandler($data, $options);
}
}
private function __attributeHandler($attribute, $options = array())
{
$attribute = array_merge($attribute['Attribute'], $attribute);
unset($attribute['Attribute']);
if (isset($attribute['Object']) && empty($attribute['Object']['id'])) {
unset($attribute['Object']);
}
if (isset($attribute['AttributeTag'])) {
$attributeTags = array();
foreach ($attribute['AttributeTag'] as $tk => $tag) {
$attribute['Tag'][$tk] = $attribute['AttributeTag'][$tk]['Tag'];
}
unset($attribute['AttributeTag']);
unset($attribute['value1']);
unset($attribute['value2']);
}
return json_encode($attribute);
}
public function header($options = array())
{
return '{"response": {"Attribute": [';
}
public function footer()
{
return ']}}' . PHP_EOL;
}
public function separator()
{
return ',';
}
}

View File

@ -8,6 +8,49 @@ class NidsExport
public $format = ""; // suricata (default), snort
public $checkWhitelist = true;
public $additional_params = array(
'contain' => array(
'Event' => array(
'fields' => array('threat_level_id')
)
)
);
public function handler($data, $options = array())
{
$continue = true;
$this->checkWhitelist = false;
if (empty($this->rules)) {
$continue = false;
}
if ($options['scope'] === 'Attribute') {
$this->export(
array($data),
$options['user']['nids_sid'],
$options['returnFormat'],
$continue
);
}
return '';
}
public function header($options = array())
{
return '';
}
public function footer()
{
return implode ("\n", $this->rules);
}
public function separator()
{
return '';
}
public function explain()
{
$this->rules[] = '# MISP export of IDS rules - optimized for '.$this->format;
@ -28,8 +71,10 @@ class NidsExport
public function export($items, $startSid, $format="suricata", $continue = false)
{
$this->format = $format;
$this->Whitelist = ClassRegistry::init('Whitelist');
$this->whitelist = $this->Whitelist->getBlockedValues();
if ($this->checkWhitelist && !isset($this->Whitelist)) {
$this->Whitelist = ClassRegistry::init('Whitelist');
$this->whitelist = $this->Whitelist->getBlockedValues();
}
// output a short explanation
if (!$continue) {
@ -105,7 +150,7 @@ class NidsExport
}
return $this->rules;
}
public function domainIpRule($ruleFormat, $attribute, &$sid)
{
$values = explode('|', $attribute['value']);
@ -558,11 +603,13 @@ class NidsExport
public function checkWhitelist($value)
{
foreach ($this->whitelist as $wlitem) {
if (preg_match($wlitem, $value)) {
return true;
}
}
if ($this->checkWhitelist) {
foreach ($this->whitelist as $wlitem) {
if (preg_match($wlitem, $value)) {
return true;
}
}
}
return false;
}

View File

@ -0,0 +1,172 @@
<?php
class OpeniocExport
{
public function buildAll($user, $data, $scope = 'event')
{
$final = '';
if (!isset($data['Attribute'])) {
$data = array('Attribute' => $data);
}
if ($scope == 'event') {
$final = $this->generateSingleTop($data);
} else {
$final = $this->generateTop($user, $data);
}
foreach ($data['Attribute'] as $attribute) {
$final .= $this->generateAttribute($attribute);
}
$final .= $this->generateBottom();
return $final;
}
public function convert($attributes)
{
$final = '';
foreach ($attributes as $attribute) {
$final .= $this->generateAttribute($attribute);
}
return $final;
}
public function getResult()
{
return $this->__final;
}
public $mapping = array(
'composite' => array(
'regkey|value' => array(array('Network', 'RegistryItem/KeyPath', 'string'), array('Network', 'RegistryItem/Value', 'string')),
'filename|md5' => array(array('FileItem', 'FileItem/FileName', 'string'), array('FileItem', 'FileItem/Md5sum', 'md5')),
'filename|sha1' => array(array('FileItem', 'FileItem/FileName', 'string'), array('FileItem', 'FileItem/Sha1sum', 'sha1')),
'filename|sha256' => array(array('FileItem', 'FileItem/FileName', 'string'), array('FileItem', 'FileItem/Sha256sum', 'sha256')),
'malware-sample' => array(array('FileItem', 'FileItem/FileName', 'string'), array('FileItem', 'FileItem/Md5sum', 'md5')),
'domain|ip' => array(array('Network', 'Network/DNS', 'string'), array('PortItem', 'PortItem/remoteIP', 'IP')),
),
'simple' => array(
'md5' => array('FileItem', 'FileItem/Md5sum', 'md5'),
'sha1' => array('FileItem', 'FileItem/Sha1sum', 'sha1'),
'sha256' => array('FileItem', 'FileItem/Sha256sum', 'sha256'),
'filename' => array('FileItem', 'FileItem/FileName', 'string'),
'ip-src' => array('PortItem', 'PortItem/remoteIP', 'IP'),
'ip-dst' => array('RouteEntryItem', 'RouteEntryItem/Destination', 'IP'),
'hostname' => array('RouteEntryItem', 'RouteEntryItem/Destination', 'string'),
'email-src' => array('Email', 'Email/From', 'string'),
'email-dst' => array('Email', 'Email/To', 'string'),
'email-subject' => array('Email', 'Email/Subject', 'string'),
'email-attachment' => array('Email', 'Email/Attachment/Name', 'string'),
'domain' => array('Network', 'Network/DNS', 'string'),
'url' => array('UrlHistoryItem', 'UrlHistoryItem/URL', 'string'),
'user-agent' => array('Network', 'Network/UserAgent', 'string'),
'regkey' => array('Network', 'RegistryItem/KeyPath', 'string'),
'snort' => array('Snort', 'Snort/Snort', 'string'),
'attachment' => array('FileItem', 'FileItem/FileName', 'string'),
'link' => array('URL', 'UrlHistoryItem/URL', 'md5')
)
);
public function frameComposite($attribute)
{
$temp = '';
$values = explode('|', $attribute['value']);
$temp .= ' <Indicator operator="AND" id="' . h($attribute['uuid']) . '">' . PHP_EOL;
$temp .= $this->frameIndicator($this->mapping['composite'][$attribute['type']][0], $attribute['uuid'], $values[0], true);
$temp .= $this->frameIndicator($this->mapping['composite'][$attribute['type']][1], $attribute['uuid'], $values[1], true);
$temp .= ' </Indicator>' . PHP_EOL;
return $temp;
}
public function frameIndicator($mapping, $uuid, $value, $extraIndent = false)
{
$temp = '';
$padding = 6;
if ($extraIndent) {
$padding = 8;
}
$temp .= str_repeat(' ', $padding) . '<IndicatorItem id="' . h($uuid) . '" condition="is">' . PHP_EOL;
$temp .= str_repeat(' ', ($padding + 2)) . '<Context document="' . $mapping[0] . '" search="' . $mapping[1] . '" type="mir" />' . PHP_EOL;
$temp .= str_repeat(' ', ($padding + 2)) . '<Content type="' . $mapping[2] . '">' . h($value) . '</Content>' . PHP_EOL;
$temp .= str_repeat(' ', $padding) . '</IndicatorItem>' . PHP_EOL;
return $temp;
}
// This method will turn each eligible attribute into an indicator
public function generateAttribute($attribute)
{
}
// Simple check for valid categories and types for IOC generation
public function checkValidTypeForIOC($attribute)
{
// categories that should be included
$Category = array('Payload delivery', 'Artifacts dropped', 'Payload installation', 'Persistence mechanism', 'Network activity');
if (!in_array($attribute['category'], $Category)) {
return false;
}
return true;
}
public function handler($attribute, $options = array())
{
$temp = '';
if (isset($attribute['Attribute'])) {
$attribute = $attribute['Attribute'];
}
// Hop over attributes that don't have the to ids flag turned on and check whether the attribute is sent for IOC export based on category/type
if (!$this->checkValidTypeForIOC($attribute) || $attribute['to_ids'] == 0) {
return false;
}
if ($attribute['type'] == 'malware-sample') {
$attribute['type'] = 'filename|md5';
}
if (strpos($attribute['type'], '|')) {
if ($this->mapping['composite'][$attribute['type']]) {
$temp .= $this->frameComposite($attribute);
}
} else {
if (isset($this->mapping['simple'][$attribute['type']])) {
$temp .= $this->frameIndicator($this->mapping['simple'][$attribute['type']], $attribute['uuid'], $attribute['value'], false);
}
}
return $temp;
}
public function header($options = array())
{
$user = $options['user'];
$temp = '';
// We will start adding all the components that will be in the xml file here
$date = date("Y-m-d\Th:i:s");
$temp .= '<?xml version="1.0" encoding="utf-8"?>' . PHP_EOL;
$temp .= '<ioc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="' . CakeText::uuid() . '" last-modified="' . $date . '" xmlns="http://schemas.mandiant.com/2010/ioc">' . PHP_EOL;
$temp .= ' <short_description>Filtered indicator list</short_description>' . PHP_EOL;
$temp .= ' <description>Filtered indicator list</description>' . PHP_EOL;
$temp .= ' <keywords />' . PHP_EOL;
$temp .= ' <authored_by>' . h($user['Organisation']['name']) . '</authored_by>' . PHP_EOL;
$temp .= ' <authored_date>' . $date . '</authored_date>' . PHP_EOL;
$temp .= ' <links />' . PHP_EOL;
$temp .= ' <definition>' . PHP_EOL;
$temp .= ' <Indicator operator="OR" id="' . CakeText::uuid() . '">' . PHP_EOL;
return $temp;
}
public function footer()
{
$temp = '';
$temp .= ' </Indicator>' . PHP_EOL;
$temp .= ' </definition>' . PHP_EOL;
$temp .= '</ioc>' . PHP_EOL;
return $temp;
}
public function separator()
{
return PHP_EOL;
}
}

View File

@ -0,0 +1,27 @@
<?php
class TextExport
{
public function handler($data, $options = array())
{
if ($options['scope'] === 'Attribute') {
return $data['Attribute']['value'];
}
return '';
}
public function header($options = array())
{
return '';
}
public function footer()
{
return "\n";
}
public function separator()
{
return "\n";
}
}

View File

@ -0,0 +1,50 @@
<?php
class XmlExport
{
public function handler($data, $options = array())
{
if ($options['scope'] === 'Attribute') {
return $this->__attributeHandler($data, $options);
} else {
return $this->__eventHandler($data, $options);
}
}
private function __attributeHandler($attribute, $options = array())
{
$attribute = array_merge($attribute['Attribute'], $attribute);
unset($attribute['Event']);
unset($attribute['Attribute']);
if (isset($attribute['Object']) && empty($attribute['Object']['id'])) {
unset($attribute['Object']);
}
if (isset($attribute['AttributeTag'])) {
$attributeTags = array();
foreach ($attribute['AttributeTag'] as $tk => $tag) {
$attribute['Tag'][$tk] = $attribute['AttributeTag'][$tk]['Tag'];
}
unset($attribute['AttributeTag']);
unset($attribute['value1']);
unset($attribute['value2']);
}
$xmlObject = Xml::fromArray(array('Attribute' => $attribute), array('format' => 'tags'));
$xmlString = $xmlObject->asXML();
return substr($xmlString, strpos($xmlString, "\n") + 1);
}
public function header($options = array())
{
return '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL . '<response>';
}
public function footer()
{
return '</response>' . PHP_EOL;
}
public function separator()
{
return '';
}
}

View File

@ -232,7 +232,8 @@ class FinancialTool
$out = array_fill(0, 25, 0);
for ($i=0;$i<strlen($input);$i++) {
if (($p=strpos($alphabet, $input[$i]))===false) {
$p = strpos($alphabet, $input[$i]);
if ($p === false) {
return false;
}
$c = $p;

View File

@ -55,7 +55,7 @@ class IOCExportTool
{
$temp = '';
// We will start adding all the components that will be in the xml file here
$date = date("Y-m-d\Th:i:s");
$date = date("Y-m-d\TH:i:s");
$temp .= '<?xml version="1.0" encoding="utf-8"?>' . PHP_EOL;
$temp .= '<ioc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="' . CakeText::uuid() . '" last-modified="' . $date . '" xmlns="http://schemas.mandiant.com/2010/ioc">' . PHP_EOL;
$temp .= ' <short_description>Filtered indicator list</short_description>' . PHP_EOL;

View File

@ -1,4 +1,5 @@
<?php
class XMLConverterTool
{
private $__toEscape = array("&", "<", ">", "\"", "'");

File diff suppressed because it is too large Load Diff

View File

@ -1194,7 +1194,8 @@ class AppModel extends Model
return $version_array;
}
public function validateAuthkey($value) {
public function validateAuthkey($value)
{
if (empty($value['authkey'])) {
return 'Empty authkey found. Make sure you set the 40 character long authkey.';
}
@ -1458,7 +1459,8 @@ class AppModel extends Model
$this->elasticSearchClient = $client;
}
public function getS3Client() {
public function getS3Client()
{
if (!$this->s3Client) {
$this->s3Client = $this->loadS3Client();
}
@ -1466,14 +1468,16 @@ class AppModel extends Model
return $this->s3Client;
}
public function loadS3Client() {
public function loadS3Client()
{
App::uses('AWSS3Client', 'Tools');
$client = new AWSS3Client();
$client->initTool();
return $client;
}
public function attachmentDirIsS3() {
public function attachmentDirIsS3()
{
// Naive way to detect if we're working in S3
return substr(Configure::read('MISP.attachments_dir'), 0, 2) === "s3";
}
@ -1655,4 +1659,84 @@ class AppModel extends Model
}
return $request;
}
// take filters in the {"OR" => [foo], "NOT" => [bar]} format along with conditions and set the conditions
public function generic_add_filter($conditions, &$filter, $keys)
{
$operator_composition = array(
'NOT' => 'AND',
'OR' => 'OR',
'AND' => 'AND'
);
if (!is_array($keys)) {
$keys = array($keys);
}
if (!isset($filter['OR']) && !isset($filter['AND']) && !isset($filter['OR'])) {
return $conditions;
}
foreach ($filter as $operator => $filters) {
$temp = array();
foreach ($filters as $f) {
// split the filter params into two lists, one for substring searches one for exact ones
if ($f[strlen($f) - 1] === '%' || $f[0] === '%') {
foreach ($keys as $key) {
if ($operator === 'NOT') {
$temp[] = array($key . ' NOT LIKE' => $f);
} else {
$temp[] = array($key . ' LIKE' => $f);
}
}
} else {
foreach ($keys as $key) {
if ($operator === 'NOT') {
$temp[$key . ' !='][] = $f;
} else {
$temp['OR'][$key][] = $f;
}
}
}
}
$conditions['AND'][] = array($operator_composition[$operator] => $temp);
if ($operator !== 'NOT') {
unset($filter[$operator]);
}
}
return $conditions;
}
/*
* Get filters in one of the following formats:
* [foo, bar]
* ["OR" => [foo, bar], "NOT" => [baz]]
* "foo"
* "foo&&bar&&!baz"
* and convert it into the same format ["OR" => [foo, bar], "NOT" => [baz]]
*/
public function convert_filters($filter)
{
if (!is_array($filter)) {
$temp = explode('&&', $filter);
$filter = array();
foreach ($temp as $f) {
if ($f[0] === '!') {
$filter['NOT'][] = $f;
} else {
$filter['OR'][] = $f;
}
}
return $filter;
}
if (!isset($filter['OR']) && !isset($filter['NOT']) && !isset($filter['AND'])) {
$temp = array();
foreach ($filter as $param) {
if ($param[0] === '!') {
$temp['NOT'][] = substr($param, 1);
} else {
$temp['OR'][] = $param;
}
}
$filter = $temp;
}
return $filter;
}
}

View File

@ -144,6 +144,7 @@ class Attribute extends AppModel
'regkey|value' => array('desc' => "Registry value + data separated by |", 'default_category' => 'Persistence mechanism', 'to_ids' => 1),
'AS' => array('desc' => 'Autonomous system', 'default_category' => 'Network activity', 'to_ids' => 0),
'snort' => array('desc' => 'An IDS rule in Snort rule-format', 'formdesc' => "An IDS rule in Snort rule-format. This rule will be automatically rewritten in the NIDS exports.", 'default_category' => 'Network activity', 'to_ids' => 1),
'bro' => array('desc' => 'An NIDS rule in the Bro rule-format', 'formdesc' => "An NIDS rule in the Bro rule-format.", 'default_category' => 'Network activity', 'to_ids' => 1),
'pattern-in-file' => array('desc' => 'Pattern in file that identifies the malware', 'default_category' => 'Payload installation', 'to_ids' => 1),
'pattern-in-traffic' => array('desc' => 'Pattern in network traffic that identifies the malware', 'default_category' => 'Network activity', 'to_ids' => 1),
'pattern-in-memory' => array('desc' => 'Pattern in memory dump that identifies the malware', 'default_category' => 'Payload installation', 'to_ids' => 1),
@ -318,7 +319,7 @@ class Attribute extends AppModel
),
'Network activity' => array(
'desc' => 'Information about network traffic generated by the malware',
'types' => array('ip-src', 'ip-dst', 'ip-dst|port', 'ip-src|port', 'port', 'hostname', 'domain', 'domain|ip', 'mac-address', 'mac-eui-64', 'email-dst', 'url', 'uri', 'user-agent', 'http-method', 'AS', 'snort', 'pattern-in-file', 'stix2-pattern', 'pattern-in-traffic', 'attachment', 'comment', 'text', 'x509-fingerprint-sha1', 'other', 'hex', 'cookie', 'hostname|port')
'types' => array('ip-src', 'ip-dst', 'ip-dst|port', 'ip-src|port', 'port', 'hostname', 'domain', 'domain|ip', 'mac-address', 'mac-eui-64', 'email-dst', 'url', 'uri', 'user-agent', 'http-method', 'AS', 'snort', 'pattern-in-file', 'stix2-pattern', 'pattern-in-traffic', 'attachment', 'comment', 'text', 'x509-fingerprint-sha1', 'other', 'hex', 'cookie', 'hostname|port', 'bro')
),
'Payload type' => array(
'desc' => 'Information about the final payload(s)',
@ -332,7 +333,7 @@ class Attribute 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 Examples: pdf-parser output, automated sandbox analysis, reverse engineering report.',
'types' => array('md5', 'sha1', 'sha256','filename', 'filename|md5', 'filename|sha1', 'filename|sha256', 'ip-src', 'ip-dst', 'ip-dst|port', 'ip-src|port', 'mac-address', 'mac-eui-64', 'hostname', 'domain', 'domain|ip', 'url', 'user-agent', 'regkey', 'regkey|value', 'AS', 'snort', 'pattern-in-file', 'pattern-in-traffic', 'pattern-in-memory', 'vulnerability', 'attachment', 'malware-sample', 'link', 'comment', 'text', 'x509-fingerprint-sha1', 'x509-fingerprint-md5', 'x509-fingerprint-sha256', 'github-repository', 'other', 'cortex')
'types' => array('md5', 'sha1', 'sha256','filename', 'filename|md5', 'filename|sha1', 'filename|sha256', 'ip-src', 'ip-dst', 'ip-dst|port', 'ip-src|port', 'mac-address', 'mac-eui-64', 'hostname', 'domain', 'domain|ip', 'url', 'user-agent', 'regkey', 'regkey|value', 'AS', 'snort', 'bro','pattern-in-file', 'pattern-in-traffic', 'pattern-in-memory', 'vulnerability', 'attachment', 'malware-sample', 'link', 'comment', 'text', 'x509-fingerprint-sha1', 'x509-fingerprint-md5', 'x509-fingerprint-sha256', 'github-repository', 'other', 'cortex')
),
'Financial fraud' => array(
'desc' => 'Financial Fraud indicators',
@ -403,7 +404,7 @@ class Attribute extends AppModel
// This helps generate quick filtering for the event view, but we may reuse this and enhance it in the future for other uses (such as the API?)
public $typeGroupings = array(
'file' => array('attachment', 'pattern-in-file', 'md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'sha512/224', 'sha512/256', 'ssdeep', 'imphash', 'impfuzzy','authentihash', 'pehash', 'tlsh', 'filename', 'filename|md5', 'filename|sha1', 'filename|sha224', 'filename|sha256', 'filename|sha384', 'filename|sha512', 'filename|sha512/224', 'filename|sha512/256', 'filename|authentihash', 'filename|ssdeep', 'filename|tlsh', 'filename|imphash', 'filename|pehash', 'malware-sample', 'x509-fingerprint-sha1', 'x509-fingerprint-sha256', 'x509-fingerprint-md5'),
'network' => array('ip-src', 'ip-dst', 'ip-src|port', 'ip-dst|port', 'mac-address', 'mac-eui-64', 'hostname', 'hostname|port', 'domain', 'domain|ip', 'email-dst', 'url', 'uri', 'user-agent', 'http-method', 'AS', 'snort', 'pattern-in-traffic', 'x509-fingerprint-md5', 'x509-fingerprint-sha1', 'x509-fingerprint-sha256'),
'network' => array('ip-src', 'ip-dst', 'ip-src|port', 'ip-dst|port', 'mac-address', 'mac-eui-64', 'hostname', 'hostname|port', 'domain', 'domain|ip', 'email-dst', 'url', 'uri', 'user-agent', 'http-method', 'AS', 'snort', 'bro','pattern-in-traffic', 'x509-fingerprint-md5', 'x509-fingerprint-sha1', 'x509-fingerprint-sha256'),
'financial' => array('btc', 'xmr', 'iban', 'bic', 'bank-account-nr', 'aba-rtn', 'bin', 'cc-number', 'prtn', 'phone-number')
);
@ -667,8 +668,7 @@ class Attribute extends AppModel
// We're working in S3
$s3 = $this->getS3Client();
$s3->delete($this->data['Attribute']['event_id'] . DS . $this->data['Attribute']['id']);
}
else {
} else {
// Standard delete
$filepath = $attachments_dir . DS . $this->data['Attribute']['event_id'] . DS . $this->data['Attribute']['id'];
$file = new File($filepath);
@ -1123,6 +1123,7 @@ class Attribute extends AppModel
case 'mutex':
case 'AS':
case 'snort':
case 'bro' :
case 'pattern-in-file':
case 'pattern-in-traffic':
case 'pattern-in-memory':
@ -2066,6 +2067,88 @@ class Attribute extends AppModel
return $rules;
}
public function set_filter_tags(&$params, $conditions, $options)
{
if (empty($params['tags'])) {
return $conditions;
}
$tag = ClassRegistry::init('Tag');
$params['tags'] = $this->dissectArgs($params['tags']);
$tagArray = $tag->fetchTagIds($params['tags'][0], $params['tags'][1]);
if (!empty($params['tags'][0]) && empty($tagArray[0])) {
$tagArray[0] = array(-1);
}
$temp = array();
if (!empty($tagArray[0])) {
$subquery_options = array(
'conditions' => array(
'tag_id' => $tagArray[0]
),
'fields' => array(
'event_id'
)
);
$lookup_field = ($options['scope'] === 'Event') ? 'Event.id' : 'Attribute.event_id';
$temp = array_merge(
$temp,
$this->subQueryGenerator($tag->EventTag, $subquery_options, $lookup_field)
);
$subquery_options = array(
'conditions' => array(
'tag_id' => $tagArray[0]
),
'fields' => array(
$options['scope'] === 'Event' ? 'Event.id' : 'attribute_id'
)
);
$lookup_field = $options['scope'] === 'Event' ? 'Event.id' : 'Attribute.id';
$temp = array_merge(
$temp,
$this->subQueryGenerator($tag->AttributeTag, $subquery_options, $lookup_field)
);
$conditions['AND'][] = array('OR' => $temp);
}
$temp = array();
if (!empty($tagArray[1])) {
if ($options['scope'] == 'all' || $options['scope'] == 'Event') {
$subquery_options = array(
'conditions' => array(
'tag_id' => $tagArray[1]
),
'fields' => array(
'event_id'
)
);
$lookup_field = ($options['scope'] === 'Event') ? 'Event.id' : 'Attribute.event_id';
$conditions['AND'][] = array_merge($temp, $this->subQueryGenerator($tag->EventTag, $subquery_options, $lookup_field, 1));
}
if ($options['scope'] == 'all' || $options['scope'] == 'Attribute') {
$subquery_options = array(
'conditions' => array(
'tag_id' => $tagArray[1]
),
'fields' => array(
$options['scope'] === 'Event' ? 'event.id' : 'attribute_id'
)
);
$lookup_field = $options['scope'] === 'Event' ? 'Event.id' : 'Attribute.id';
$conditions['AND'][] = array_merge($temp, $this->subQueryGenerator($tag->AttributeTag, $subquery_options, $lookup_field, 1));
}
}
$params['tags'] = array();
if (!empty($tagArray[0]) && empty($options['pop'])) {
$params['tags']['OR'] = $tagArray[0];
}
if (!empty($tagArray[1])) {
$params['tags']['NOT'] = $tagArray[1];
}
if (empty($params['tags'])) {
unset($params['tags']);
}
return $conditions;
}
public function text($user, $type, $tags = false, $eventId = false, $allowNonIDS = false, $from = false, $to = false, $last = false, $enforceWarninglist = false, $allowNotPublished = false)
{
//permissions are taken care of in fetchAttributes()
@ -2092,56 +2175,8 @@ class Attribute extends AppModel
if ($eventId !== false) {
$conditions['AND'][] = array('Event.id' => $eventId);
} elseif ($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->fetchTagIds($args[0], $args[1]);
$temp = array();
if (!empty($tagArray[0])) {
$options = array(
'conditions' => array(
'tag_id' => $tagArray[0]
),
'fields' => array(
'event_id'
)
);
$temp = array_merge($temp, $this->subQueryGenerator($tag->EventTag, $options, 'Attribute.event_id'));
$options = array(
'conditions' => array(
'tag_id' => $tagArray[0]
),
'fields' => array(
'attribute_id'
)
);
$temp = array_merge($temp, $this->subQueryGenerator($tag->AttributeTag, $options, 'Attribute.id'));
$temp2 = array('OR' => $temp);
$conditions['AND'][] = $temp2;
}
$temp = array();
if (!empty($tagArray[1])) {
$options = array(
'conditions' => array(
'tag_id' => $tagArray[1]
),
'fields' => array(
'event_id'
)
);
$temp = array_merge($temp, $this->subQueryGenerator($tag->EventTag, $options, 'Attribute.event_id', 1));
$options = array(
'conditions' => array(
'tag_id' => $tagArray[1]
),
'fields' => array(
'attribute_id'
)
);
$temp = array_merge($temp, $this->subQueryGenerator($tag->AttributeTag, $options, 'Attribute.id', 1));
$temp2 = array('AND' => $temp);
$conditions['AND'][] = $temp2;
}
$passed_param = array('tags' => $tags);
$conditions = $this->set_filter_tags($passed_params, $conditions);
}
$attributes = $this->fetchAttributes($user, array(
'conditions' => $conditions,
@ -2417,25 +2452,26 @@ class Attribute extends AppModel
// array 1 will have all of the non negated terms and array 2 all the negated terms
public function dissectArgs($args)
{
if (!$args) {
return array(null, null);
if (!is_array($args)) {
$args = explode('&&', $args);
}
if (is_array($args)) {
$argArray = $args;
$result = array(0 => array(), 1 => array());
if (isset($args['OR']) || isset($args['NOT']) || isset($args['AND'])) {
if (!empty($args['OR'])) {
$result[0] = $args['OR'];
}
if (!empty($args['NOT'])) {
$result[1] = $args['NOT'];
}
} else {
$argArray = explode('&&', $args);
}
$accept = $reject = $result = array();
$reject = array();
foreach ($argArray as $arg) {
if (substr($arg, 0, 1) == '!') {
$reject[] = substr($arg, 1);
} else {
$accept[] = $arg;
foreach ($args as $arg) {
if (substr($arg, 0, 1) == '!') {
$result[1][] = substr($arg, 1);
} else {
$result[0][] = $arg;
}
}
}
$result[0] = $accept;
$result[1] = $reject;
return $result;
}
@ -2723,7 +2759,7 @@ class Attribute extends AppModel
// conditions
// order
// group
public function fetchAttributes($user, $options = array())
public function fetchAttributes($user, $options = array(), &$continue = true)
{
$params = array(
'conditions' => $this->buildConditions($user),
@ -2749,8 +2785,6 @@ class Attribute extends AppModel
}
if (isset($options['limit'])) {
$params['limit'] = $options['limit'];
} else {
$option['contain']['Event']['fields'] = array('id', 'info', 'org_id', 'orgc_id');
}
if (Configure::read('MISP.proposals_block_attributes') && isset($options['conditions']['AND']['Attribute.to_ids']) && $options['conditions']['AND']['Attribute.to_ids'] == 1) {
$this->bindModel(array('hasMany' => array('ShadowAttribute' => array('foreignKey' => 'old_id'))));
@ -2820,9 +2854,8 @@ class Attribute extends AppModel
$this->Warninglist = ClassRegistry::init('Warninglist');
$warninglists = $this->Warninglist->fetchForEventView();
}
if (empty($params['limit'])) {
$loopLimit = 100000;
$loopLimit = 50000;
$loop = true;
$params['limit'] = $loopLimit;
$params['page'] = 0;
@ -2831,7 +2864,6 @@ class Attribute extends AppModel
$pagesToFetch = 1;
}
$attributes = array();
$continue = true;
while ($continue) {
if ($loop) {
$params['page'] = $params['page'] + 1;
@ -2839,13 +2871,17 @@ class Attribute extends AppModel
$continue = false;
continue;
}
} else {
$continue = false;
}
$results = $this->find('all', $params);
if (!$loop) {
if (!empty($params['limit']) && count($results) < $params['limit']) {
$continue = false;
}
$break = true;
}
// return false if we're paginating
if (isset($options['limit']) && empty($results)) {
return false;
return array();
}
$results = array_values($results);
$proposals_block_attributes = Configure::read('MISP.proposals_block_attributes');
@ -2871,6 +2907,9 @@ class Attribute extends AppModel
}
$attributes[] = $results[$key];
}
if (!empty($break)) {
break;
}
}
return $attributes;
}
@ -3126,11 +3165,11 @@ class Attribute extends AppModel
if (is_array($timestamp)) {
$timestamp[0] = $this->Event->resolveTimeDelta($timestamp[0]);
$timestamp[1] = $this->Event->resolveTimeDelta($timestamp[1]);
$conditions['AND'][] = array($scope . ' >=' => $timestamp[0]);
$conditions['AND'][] = array($scope . ' <=' => $timestamp[1]);
$conditions['AND'][] = array($scope . ' >=' => intval($timestamp[0]));
$conditions['AND'][] = array($scope . ' <=' => intval($timestamp[1]));
} else {
$timestamp = $this->Event->resolveTimeDelta($timestamp);
$conditions['AND'][] = array($scope . ' >=' => $timestamp);
$conditions['AND'][] = array($scope . ' >=' => intval($timestamp));
}
return $conditions;
}
@ -3543,6 +3582,7 @@ class Attribute extends AppModel
}
return true;
}
public function attachValidationWarnings($adata)
{
if (!$this->__fTool) {
@ -3553,4 +3593,52 @@ class Attribute extends AppModel
}
return $adata;
}
public function buildFilterConditions($user, &$params)
{
$conditions = $this->buildConditions($user);
$attribute_conditions = array();
$object_conditions = array();
$simple_params = array(
'Attribute' => array(
'value' => array('function' => 'set_filter_value'),
'category' => array('function' => 'set_filter_simple_attribute'),
'type' => array('function' => 'set_filter_simple_attribute'),
'tags' => array('function' => 'set_filter_tags'),
'uuid' => array('function' => 'set_filter_uuid'),
'deleted' => array('function' => 'set_filter_deleted')
),
'Event' => array(
'eventid' => array('function' => 'set_filter_eventid'),
'ignore' => array('function' => 'set_filter_ignore'),
'tags' => array('function' => 'set_filter_tags'),
'tag' => array('function' => 'set_filter_tags'),
'from' => array('function' => 'set_filter_timestamp'),
'to' => array('function' => 'set_filter_timestamp'),
'last' => array('function' => 'set_filter_timestamp'),
'timestamp' => array('function' => 'set_filter_timestamp'),
'publish_timestamp' => array('function' => 'set_filter_timestamp'),
'org' => array('function' => 'set_filter_org'),
'uuid' => array('function' => 'set_filter_uuid'),
'published' => array('function' => 'set_filter_published')
),
'Object' => array(
'object_name' => array('function' => 'set_filter_object_name'),
'deleted' => array('function' => 'set_filter_deleted')
)
);
foreach ($params as $param => $paramData) {
foreach ($simple_params as $scope => $simple_param_scoped) {
if (isset($simple_param_scoped[$param]) && $params[$param] !== false) {
$options = array(
'filter' => $param,
'scope' => $scope,
'pop' => !empty($simple_param_scoped[$param]['pop'])
);
$conditions = $this->Event->{$simple_param_scoped[$param]['function']}($params, $conditions, $options);
}
}
}
return $conditions;
}
}

View File

@ -913,7 +913,8 @@ class Event extends AppModel
return 'Success';
}
private function __prepareForPushToServer($event, $server) {
private function __prepareForPushToServer($event, $server)
{
if ($event['Event']['distribution'] == 4) {
if (!empty($event['SharingGroup']['SharingGroupServer'])) {
$found = false;
@ -965,6 +966,7 @@ class Event extends AppModel
}
return $jsonArray['name'];
}
// no break
case '302': // Found
$newLocation = $response->headers['Location'];
$newTextBody = $response->body();
@ -984,7 +986,9 @@ class Event extends AppModel
public function restfulEventToServer($event, $server, $urlPath, &$newLocation, &$newTextBody, $HttpSocket = null)
{
$event = $this->__prepareForPushToServer($event, $server);
if (is_numeric($event)) return $event;
if (is_numeric($event)) {
return $event;
}
$url = $server['Server']['url'];
$HttpSocket = $this->setupHttpSocket($server, $HttpSocket);
$request = $this->setupSyncRequest($server);
@ -1028,7 +1032,8 @@ class Event extends AppModel
return $data;
}
private function __prepareAttributesForSync($data, $server) {
private function __prepareAttributesForSync($data, $server)
{
// prepare attribute for sync
if (!empty($data['Attribute'])) {
foreach ($data['Attribute'] as $key => $attribute) {
@ -1044,7 +1049,8 @@ class Event extends AppModel
return $data;
}
private function __prepareObjectsForSync($data, $server) {
private function __prepareObjectsForSync($data, $server)
{
// prepare Object for sync
if (!empty($data['Object'])) {
foreach ($data['Object'] as $key => $object) {
@ -1288,6 +1294,69 @@ class Event extends AppModel
return $conditions;
}
public function filterEventIds($user, &$params = array())
{
$conditions = $this->createEventConditions($user);
$simple_params = array(
'Event' => array(
'eventid' => array('function' => 'set_filter_eventid', 'pop' => true),
'ignore' => array('function' => 'set_filter_ignore'),
'tags' => array('function' => 'set_filter_tags'),
'tag' => array('function' => 'set_filter_tags'),
'from' => array('function' => 'set_filter_timestamp', 'pop' => true),
'to' => array('function' => 'set_filter_timestamp', 'pop' => true),
'last' => array('function' => 'set_filter_timestamp', 'pop' => true),
'timestamp' => array('function' => 'set_filter_timestamp', 'pop' => true),
'publish_timestamp' => array('function' => 'set_filter_timestamp', 'pop' => true),
'org' => array('function' => 'set_filter_org', 'pop' => true),
'uuid' => array('function' => 'set_filter_uuid', 'pop' => true),
'published' => array('function' => 'set_filter_published', 'pop' => true)
),
'Object' => array(
'object_name' => array('function' => 'set_filter_object_name')
),
'Attribute' => array(
'value' => array('function' => 'set_filter_value', 'pop' => true),
'category' => array('function' => 'set_filter_simple_attribute'),
'type' => array('function' => 'set_filter_simple_attribute'),
'tags' => array('function' => 'set_filter_tags', 'pop' => true),
'uuid' => array('function' => 'set_filter_uuid')
)
);
foreach ($params as $param => $paramData) {
foreach ($simple_params as $scope => $simple_param_scoped) {
if (isset($simple_param_scoped[$param]) && $params[$param] !== false) {
$options = array(
'filter' => $param,
'scope' => $scope,
'pop' => !empty($simple_param_scoped[$param]['pop'])
);
if ($scope === 'Event') {
$conditions = $this->{$simple_param_scoped[$param]['function']}($params, $conditions, $options);
} else {
$temp = array();
$temp = $this->{$simple_param_scoped[$param]['function']}($params, $temp, $options);
if (!empty($temp)) {
$subQueryOptions = array(
'conditions' => $temp,
'fields' => array(
'event_id'
)
);
$conditions['AND'][] = $this->subQueryGenerator($this->{$scope}, $subQueryOptions, 'Event.id');
}
}
}
}
}
$results = array_values($this->find('list', array(
'conditions' => $conditions,
'recursive' => -1,
'fields' => array('Event.id')
)));
return $results;
}
public function fetchSimpleEventIds($user, $params = array())
{
$conditions = $this->createEventConditions($user);
@ -1891,90 +1960,227 @@ class Event extends AppModel
$field = '"' . $field . '"';
}
public function csv($user, $eventid=false, $ignore=false, $attributeIDList = array(), $tags = false, $category = false, $type = false, $includeContext = false, $from = false, $to = false, $last = false, $enforceWarninglist = false, $value = false, $timestamp = false)
public function set_filter_org(&$params, $conditions, $options)
{
$this->recursive = -1;
$conditions = array();
// If we are not in the search result csv download function then we need to check what can be downloaded. CSV downloads are already filtered by the search function.
if ($eventid !== 'search') {
if ($from) {
$conditions['AND']['Event.date >='] = $from;
}
if ($to) {
$conditions['AND']['Event.date <='] = $to;
}
if ($last) {
$conditions['AND']['Event.publish_timestamp >='] = $last;
}
if ($timestamp) {
$conditions['AND']['Attribute.timestamp >='] = $timestamp;
$conditions['AND']['Event.timestamp >='] = $timestamp;
}
// This is for both single event downloads and for full downloads. Org has to be the same as the user's or distribution not org only - if the user is no siteadmin
if ($ignore == false) {
$conditions['AND']['Event.published'] = 1;
}
if (!empty($params['org'])) {
$params['org'] = $this->convert_filters($params['org']);
if (!empty($params['org']['OR'])) {
foreach ($params['org']['OR'] as $k => $org) {
if (!is_numeric($org)) {
$existingOrg = $this->Orgc->find('first', array(
'recursive' => -1,
'conditions' => array('Orgc.name' => $org),
'fields' => array('Orgc.name', 'Orgc.id')
));
if (empty($existingOrg)) {
$params['org']['OR'][$k] = -1;
} else {
$params['org']['OR'][$k] = $existingOrg['Orgc']['id'];
}
}
}
}
if (!empty($params['org']['NOT'])) {
$temp = array();
foreach ($params['org']['NOT'] as $org) {
if (!is_numeric($org)) {
$existingOrg = $this->Orgc->find('first', array(
'recursive' => -1,
'conditions' => array('Orgc.name' => $org),
'fields' => array('Orgc.name', 'Orgc.id')
));
if (!empty($existingOrg)) {
$temp[] = $existingOrg['Orgc']['id'];
}
} else {
$temp[] = $org;
}
}
if (!empty($temp)) {
$params['org']['NOT'] = $temp;
} else {
unset($params['org']['NOT']);
}
}
$conditions = $this->generic_add_filter($conditions, $params['org'], 'Event.orgc_id');
}
return $conditions;
}
// If we sent any tags along, load the associated tag names for each attribute
if ($tags) {
$tag = ClassRegistry::init('Tag');
$args = $this->Attribute->dissectArgs($tags);
$tagArray = $tag->fetchEventTagIds($args[0], $args[1]);
$temp = array();
foreach ($tagArray[0] as $accepted) {
$temp['OR'][] = array('Event.id' => $accepted);
}
if (!empty($temp)) {
$conditions['AND'][] = $temp;
}
$temp = array();
foreach ($tagArray[1] as $rejected) {
$temp['AND'][] = array('Event.id !=' => $rejected);
}
if (!empty($temp)) {
$conditions['AND'][] = $temp;
}
}
// if we're downloading a single event, set it as a condition
if ($eventid) {
$conditions['AND'][] = array('Event.id' => $eventid);
}
public function set_filter_eventid(&$params, $conditions, $options)
{
if (!empty($params['eventid']) && $params['eventid'] !== 'all') {
$params['eventid'] = $this->convert_filters($params['eventid']);
$conditions = $this->generic_add_filter($conditions, $params['eventid'], 'Event.id');
}
return $conditions;
}
//restricting to non-private or same org if the user is not a site-admin.
if (!$ignore) {
$conditions['AND']['Attribute.to_ids'] = 1;
public function set_filter_uuid(&$params, $conditions, $options)
{
if (!empty($params['uuid'])) {
$params['uuid'] = $this->convert_filters($params['uuid']);
if (!empty($options['scope']) || $options['scope'] === 'Event') {
$conditions = $this->generic_add_filter($conditions, $params['uuid'], 'Event.uuid');
}
if ($type) {
$conditions['AND']['Attribute.type'] = $type;
}
if ($category) {
$conditions['AND']['Attribute.category'] = $category;
}
if ($value) {
$temp = array(
'OR' => array(
'Attribute.value1' => $value,
'Attribute.value2' => $value
)
);
$conditions['AND'][] = $temp;
if (!empty($options['scope']) || $options['scope'] === 'Attribute') {
$conditions = $this->generic_add_filter($conditions, $params['uuid'], 'Attribute.uuid');
}
}
return $conditions;
}
if ($eventid === 'search') {
foreach ($attributeIDList as $aID) {
public function set_filter_deleted(&$params, $conditions, $options)
{
if (!empty($params['deleted'])) {
if (empty($options['scope'])) {
$scope = 'Attribute';
} else {
$scope = $options['scope'];
}
if ($params['deleted'])
$conditions = $this->
$conditions = $this->generic_add_filter($conditions, $params['deleted'], $scope . '.deleted');
}
return $conditions;
}
public function set_filter_ignore(&$params, $conditions, $options)
{
if (empty($params['ignore'])) {
$conditions['AND']['Event.published'] = 1;
$conditions['AND']['Attribute.to_ids'] = 1;
}
return $conditions;
}
public function set_filter_published(&$params, $conditions, $options)
{
if (isset($params['published'])) {
$conditions['AND']['Event.published'] = $params['published'];
}
return $conditions;
}
public function set_filter_tags(&$params, $conditions, $options)
{
if (!empty($params['tags'])) {
$conditions = $this->Attribute->set_filter_tags($params, $conditions, $options);
}
return $conditions;
}
public function set_filter_simple_attribute(&$params, $conditions, $options)
{
if (!empty($params[$options['filter']])) {
$params[$options['filter']] = $this->convert_filters($params[$options['filter']]);
$conditions = $this->generic_add_filter($conditions, $params[$options['filter']], 'Attribute.' . $options['filter']);
}
return $conditions;
}
public function set_filter_attribute_id(&$params, $conditions, $options)
{
if (!empty($params[$options['filter']])) {
$params[$options['filter']] = $this->convert_filters($params[$options['filter']]);
$conditions = $this->generic_add_filter($conditions, $params[$options['filter']], 'Attribute.' . $options['filter']);
}
return $conditions;
}
public function set_filter_value(&$params, $conditions, $options)
{
if (!empty($params['value'])) {
$params[$options['filter']] = $this->convert_filters($params[$options['filter']]);
$conditions = $this->generic_add_filter($conditions, $params[$options['filter']], array('Attribute.value1', 'Attribute.value2'));
}
return $conditions;
}
public function set_filter_timestamp(&$params, $conditions, $options)
{
if ($options['filter'] == 'from') {
$conditions['AND']['Event.date >='] = $params['from'];
} elseif ($options['filter'] == 'to') {
$conditions['AND']['Event.date <='] = $params['to'];
} else {
$filters = array(
'timestamp' => array(
'Event.timestamp'
),
'publish_timestamp' => array(
'Event.publish_timestamp'
),
'last' => array(
'Event.publish_timestamp'
)
);
foreach ($filters[$options['filter']] as $f) {
$conditions = $this->Attribute->setTimestampConditions($params[$options['filter']], $conditions, $f);
}
}
return $conditions;
}
public function csv($user, $params, $search = false, &$continue = true)
{
$conditions = array();
$simple_params = array(
'eventid' => array('function' => 'set_filter_eventid'),
'ignore' => array('function' => 'set_filter_ignore'),
'tags' => array('function' => 'set_filter_tags'),
'category' => array('function' => 'set_filter_simple_attribute'),
'type' => array('function' => 'set_filter_simple_attribute'),
'from' => array('function' => 'set_filter_timestamp'),
'to' => array('function' => 'set_filter_timestamp'),
'last' => array('function' => 'set_filter_timestamp'),
'value' => array('function' => 'set_filter_value'),
'timestamp' => array('function' => 'set_filter_timestamp'),
'attributeIDList' => array('functon' => 'set_filter_attribute_id')
);
foreach ($params as $param => $paramData) {
if (isset($simple_params[$param]) && $params[$param] !== false) {
$options = array(
'filter' => $param,
'scope' => 'Event',
'pop' => !empty($simple_param_scoped[$param]['pop'])
);
$conditions = $this->{$simple_params[$param]['function']}($params, $conditions, $options);
}
}
//$attributeIDList = array(), $includeContext = false, $enforceWarninglist = false
$this->recursive = -1;
if (!empty($params['eventid']) && $params['eventid'] === 'search') {
foreach ($params['attributeIDList'] as $aID) {
$conditions['AND']['OR'][] = array('Attribute.id' => $aID);
}
}
$params = array(
$csv_params = array(
'conditions' => $conditions, //array of conditions
'fields' => array('Attribute.event_id', 'Attribute.distribution', 'Attribute.category', 'Attribute.type', 'Attribute.value', 'Attribute.comment', 'Attribute.uuid', 'Attribute.to_ids', 'Attribute.timestamp', 'Attribute.id', 'Attribute.object_relation'),
'order' => array('Attribute.uuid ASC'),
'enforceWarninglist' => $enforceWarninglist,
'flatten' => true
);
// copy over the parameters that have to deal with pagination or additional functionality to be executed
$control_params = array(
'limit', 'page', 'enforceWarninglist'
);
foreach ($control_params as $control_param) {
if (!empty($params[$control_param])) {
$csv_params[$control_param] = $params[$control_param];
}
}
$csv_params = $this->__appendIncludesCSV($csv_params, !empty($params['includeContext']));
$attributes = $this->Attribute->fetchAttributes($user, $csv_params, $continue);
$attributes = $this->__sanitiseCSVAttributes($attributes, !empty($params['includeContext']), !empty($params['ignore']));
return $attributes;
}
private function __appendIncludesCSV($params, $includeContext)
{
if ($includeContext) {
$params['contain'] = array(
'Event' => array(
@ -1994,9 +2200,14 @@ class Event extends AppModel
);
}
$params['contain']['Object'] = array('fields' => array('id', 'uuid', 'name', 'meta-category'));
$attributes = $this->Attribute->fetchAttributes($user, $params);
if (empty($attributes)) {
return array();
return $params;
}
private function __sanitiseCSVAttributes($attributes, $includeContext, $ignore)
{
if (!empty($ignore)) {
$this->Whitelist = ClassRegistry::init('Whitelist');
$attributes = $this->Whitelist->removeWhitelistedFromArray($attributes, true);
}
foreach ($attributes as &$attribute) {
$this->__escapeCSVField($attribute['Attribute']['value']);
@ -2354,6 +2565,20 @@ class Event extends AppModel
if (empty($orgMembers)) {
return false;
}
$temp = $this->__buildContactEventEmailBody($user, $message, $event, $targetUser, $id);
$bodyevent = $temp[0];
$body = $temp[1];
$result = true;
$tplColorString = !empty(Configure::read('MISP.email_subject_TLP_string')) ? Configure::read('MISP.email_subject_TLP_string') : "TLP Amber";
foreach ($orgMembers as &$reporter) {
$subject = "[" . Configure::read('MISP.org') . " MISP] Need info about event " . $id . " - ".$tplColorString;
$result = $this->User->sendEmail($reporter, $bodyevent, $body, $subject, $user) && $result;
}
return $result;
}
private function __buildContactEventEmailBody($user, $message, $event, $targetUser, $id)
{
// The mail body, h() is NOT needed as we are sending plain-text mails.
$body = "";
$body .= "Hello, \n";
@ -2415,13 +2640,7 @@ class Event extends AppModel
}
$bodyevent .= "\n";
$bodyevent .= $bodyTempOther; // append the 'other' attribute types to the bottom.
$result = true;
$tplColorString = !empty(Configure::read('MISP.email_subject_TLP_string')) ? Configure::read('MISP.email_subject_TLP_string') : "TLP Amber";
foreach ($orgMembers as &$reporter) {
$subject = "[" . Configure::read('MISP.org') . " MISP] Need info about event " . $id . " - ".$tplColorString;
$result = $this->User->sendEmail($reporter, $bodyevent, $body, $subject, $user) && $result;
}
return $result;
return array($bodyevent, $body);
}
private function __captureSGForElement($element, $user)
@ -3184,7 +3403,8 @@ class Event extends AppModel
}
}
private function __getPrioWorkerIfPossible() {
private function __getPrioWorkerIfPossible()
{
$this->ResqueStatus = new ResqueStatus\ResqueStatus(Resque::redis());
$workers = $this->ResqueStatus->getWorkers();
$workerType = 'default';
@ -3755,18 +3975,22 @@ class Event extends AppModel
public function resolveTimeDelta($delta)
{
if (is_int($delta)) {
if (is_numeric($delta)) {
return $delta;
}
$multiplierArray = array('d' => 86400, 'h' => 3600, 'm' => 60);
$multiplierArray = array('d' => 86400, 'h' => 3600, 'm' => 60, 's' => 1);
$multiplier = $multiplierArray['d'];
$lastChar = strtolower(substr($delta, -1));
if (!is_numeric($lastChar) && array_key_exists($lastChar, $multiplierArray)) {
$multiplier = $multiplierArray[$lastChar];
$delta = substr($delta, 0, -1);
} else {
// invalid filter, make sure we don't return anything
return time() + 1;
}
if (!is_numeric($delta)) {
return false;
// Same here. (returning false dumps the whole database)
return time() + 1;
}
return time() - ($delta * $multiplier);
}
@ -4341,7 +4565,7 @@ class Event extends AppModel
if ($parameterKey === 'org') {
$found_orgs = $this->Org->find('all', array(
'recursive' => -1,
'conditions' => array('LOWER(name) LIKE' => '%' . strtolower(substr($v, 1)) . '%'),
'conditions' => array('name' => substr($v, 1)),
));
foreach ($found_orgs as $o) {
$subcondition['AND'][] = array('Event.orgc_id !=' => $o['Org']['id']);
@ -4356,7 +4580,12 @@ class Event extends AppModel
$subcondition['AND'][] = array('Event.uuid !=' => substr($v, 1));
$subcondition['AND'][] = array('Attribute.uuid !=' => substr($v, 1));
} else {
$subcondition['AND'][] = array('Attribute.' . $parameterKey . ' NOT LIKE' => '%'.substr($v, 1).'%');
$lookup = substr($v, 1);
if (strlen($lookup) != strlen(trim($lookup, '%'))) {
$subcondition['AND'][] = array('Attribute.' . $parameterKey . ' NOT LIKE' => $lookup);
} else {
$subcondition['AND'][] = array('NOT' => array('Attribute.' . $parameterKey => $lookup));
}
}
}
} else {
@ -4372,7 +4601,7 @@ class Event extends AppModel
if ($parameterKey === 'org') {
$found_orgs = $this->Org->find('all', array(
'recursive' => -1,
'conditions' => array('LOWER(name) LIKE' => '%' . strtolower($v) . '%'),
'conditions' => array('name' => $v),
));
foreach ($found_orgs as $o) {
$subcondition['OR'][] = array('Event.orgc_id' => $o['Org']['id']);
@ -4388,7 +4617,11 @@ class Event extends AppModel
$subcondition['OR'][] = array('Event.uuid' => $v);
} else {
if (!empty($v)) {
$subcondition['OR'][] = array('Attribute.' . $parameterKey . ' LIKE' => '%'.$v.'%');
if (strlen($v) != strlen(trim($v, '%'))) {
$subcondition['AND'][] = array('Attribute.' . $parameterKey . ' LIKE' => $v);
} else {
$subcondition['AND'][] = array('Attribute.' . $parameterKey => $v);
}
}
}
}

View File

@ -229,7 +229,8 @@ class Feed extends AppModel
if ($doFetch) {
$fetchIssue = false;
try {
$response = $this->__getRecursive($feed['Feed']['url'], '', array());
$request = $this->__createFeedRequest($feed['Feed']['headers']);
$response = $this->__getRecursive($feed['Feed']['url'], '', $request);
//$response = $HttpSocket->get($feed['Feed']['url'], '', array());
} catch (Exception $e) {
return $e->getMessage();

View File

@ -1783,7 +1783,8 @@ class Server extends AppModel
return true;
}
private function __getEventIdListBasedOnPullTechnique($technique, $server) {
private function __getEventIdListBasedOnPullTechnique($technique, $server)
{
if ("full" === $technique) {
// get a list of the event_ids on the server
$eventIds = $this->getEventIdsFromServer($server);
@ -1819,6 +1820,165 @@ class Server extends AppModel
return $eventIds;
}
private function __checkIfEventIsBlockedBeforePull($event)
{
if (Configure::read('MISP.enableEventBlacklisting') !== false) {
$this->EventBlacklist = ClassRegistry::init('EventBlacklist');
$r = $this->EventBlacklist->find('first', array('conditions' => array('event_uuid' => $event['Event']['uuid'])));
if (!empty($r)) {
return true;
}
}
return false;
}
private function __updatePulledEventBeforeInsert($event, $server, $user)
{
// we have an Event array
// The event came from a pull, so it should be locked.
$event['Event']['locked'] = true;
if (!isset($event['Event']['distribution'])) { // version 1
$event['Event']['distribution'] = '1';
}
// Distribution
if (empty(Configure::read('MISP.host_org_id')) || !$server['Server']['internal'] || Configure::read('MISP.host_org_id') != $server['Server']['org_id']) {
switch ($event['Event']['distribution']) {
case 1:
// if community only, downgrade to org only after pull
$event['Event']['distribution'] = '0';
break;
case 2:
// if connected communities downgrade to community only
$event['Event']['distribution'] = '1';
break;
}
if (isset($event['Event']['Attribute']) && !empty($event['Event']['Attribute'])) {
foreach ($event['Event']['Attribute'] as $key => $a) {
switch ($a['distribution']) {
case '1':
$event['Event']['Attribute'][$key]['distribution'] = '0';
break;
case '2':
$event['Event']['Attribute'][$key]['distribution'] = '1';
break;
}
}
}
}
// Distribution, set reporter of the event, being the admin that initiated the pull
$event['Event']['user_id'] = $user['id'];
return $event;
}
private function __checkIfPulledEventExistsAndAddOrUpdate($event, &$successes, &$fails, $eventModel, $server, $user, $passAlong, $job, $jobId)
{
// check if the event already exist (using the uuid)
$existingEvent = null;
$existingEvent = $eventModel->find('first', array('conditions' => array('Event.uuid' => $event['Event']['uuid'])));
if (!$existingEvent) {
// add data for newly imported events
$passAlong = $server['Server']['id'];
$result = $eventModel->_add($event, true, $user, $server['Server']['org_id'], $passAlong, true, $jobId);
if ($result) {
$successes[] = $eventId;
} else {
$fails[$eventId] = 'Failed (partially?) because of validation errors: '. json_encode($eventModel->validationErrors, true);
}
} else {
$tempUser = $user;
$tempUser['Role']['perm_site_admin'] = 0;
$result = $eventModel->_edit($event, $tempUser, $existingEvent['Event']['id'], $jobId);
if ($result === true) {
$successes[] = $eventId;
} elseif (isset($result['error'])) {
$fails[$eventId] = $result['error'];
} else {
$fails[$eventId] = json_encode($result);
}
}
}
private function __pullEvents($eventId, $successes, $fails, $eventModel, $server, $user, $passAlong, $job, $jobId)
{
$event = $eventModel->downloadEventFromServer(
$eventId,
$server
);
if (!empty($event)) {
if ($this->__checkIfEventIsBlockedBeforePull($event)) {
return false;
}
$this->__updatePulledEventBeforeInsert($event, $server, $user);
$this->__checkIfPulledEventExistsAndAddOrUpdate($event, $successes, $fails, $eventModel, $server, $user, $passAlong, $job, $jobId);
} else {
// error
$fails[$eventId] = 'failed downloading the event';
}
if ($jobId) {
if ($k % 10 == 0) {
$job->id = $jobId;
$job->saveField('progress', 50 * (($k + 1) / count($eventIds)));
}
}
return true;
}
private function __handlePulledProposals($proposals, $events, $job, $jobId)
{
$pulledProposals = array();
if (!empty($proposals)) {
$shadowAttribute = ClassRegistry::init('ShadowAttribute');
$shadowAttribute->recursive = -1;
$uuidEvents = array_flip($events);
foreach ($proposals as $k => &$proposal) {
$proposal = $proposal['ShadowAttribute'];
$oldsa = $shadowAttribute->findOldProposal($proposal);
$proposal['event_id'] = $uuidEvents[$proposal['event_uuid']];
if (!$oldsa || $oldsa['timestamp'] < $proposal['timestamp']) {
if ($oldsa) {
$shadowAttribute->delete($oldsa['id']);
}
if (!isset($pulledProposals[$proposal['event_id']])) {
$pulledProposals[$proposal['event_id']] = 0;
}
$pulledProposals[$proposal['event_id']]++;
if (isset($proposal['old_id'])) {
$oldAttribute = $eventModel->Attribute->find('first', array('recursive' => -1, 'conditions' => array('uuid' => $proposal['uuid'])));
if ($oldAttribute) {
$proposal['old_id'] = $oldAttribute['Attribute']['id'];
} else {
$proposal['old_id'] = 0;
}
}
// check if this is a proposal from an old MISP instance
if (!isset($proposal['Org']) && isset($proposal['org']) && !empty($proposal['org'])) {
$proposal['Org'] = $proposal['org'];
$proposal['EventOrg'] = $proposal['event_org'];
} elseif (!isset($proposal['Org']) && !isset($proposal['EventOrg'])) {
continue;
}
$proposal['org_id'] = $this->Organisation->captureOrg($proposal['Org'], $user);
$proposal['event_org_id'] = $this->Organisation->captureOrg($proposal['EventOrg'], $user);
unset($proposal['Org']);
unset($proposal['EventOrg']);
$shadowAttribute->create();
if (!isset($proposal['deleted']) || !$proposal['deleted']) {
if ($shadowAttribute->save($proposal)) {
$shadowAttribute->sendProposalAlertEmail($proposal['event_id']);
}
}
}
if ($jobId) {
if ($k % 50 == 0) {
$job->id = $jobId;
$job->saveField('progress', 50 * (($k + 1) / count($proposals)));
}
}
}
}
return $pulledProposals;
}
public function pull($user, $id = null, $technique=false, $server, $jobId = false, $percent = 100, $current = 0)
{
if ($jobId) {
@ -1826,6 +1986,7 @@ class Server extends AppModel
$job->read(null, $jobId);
$email = "Scheduled job";
} else {
$job = false;
$email = $user['email'];
}
$eventModel = ClassRegistry::init('Event');
@ -1856,101 +2017,12 @@ class Server extends AppModel
}
$successes = array();
$fails = array();
$pulledProposals = array();
// now process the $eventIds to pull each of the events sequentially
if (!empty($eventIds)) {
// download each event
if (null != $eventIds) {
$HttpSocket = $this->setupHttpSocket($server);
foreach ($eventIds as $k => $eventId) {
$event = $eventModel->downloadEventFromServer(
$eventId,
$server
);
if (null != $event) {
$blocked = false;
if (Configure::read('MISP.enableEventBlacklisting') !== false) {
$this->EventBlacklist = ClassRegistry::init('EventBlacklist');
$r = $this->EventBlacklist->find('first', array('conditions' => array('event_uuid' => $event['Event']['uuid'])));
if (!empty($r)) {
continue;
}
}
// we have an Event array
// The event came from a pull, so it should be locked.
$event['Event']['locked'] = true;
if (!isset($event['Event']['distribution'])) { // version 1
$event['Event']['distribution'] = '1';
}
// Distribution
if (empty(Configure::read('MISP.host_org_id')) || !$server['Server']['internal'] || Configure::read('MISP.host_org_id') != $server['Server']['org_id']) {
switch ($event['Event']['distribution']) {
case 1:
// if community only, downgrade to org only after pull
$event['Event']['distribution'] = '0';
break;
case 2:
// if connected communities downgrade to community only
$event['Event']['distribution'] = '1';
break;
}
if (isset($event['Event']['Attribute']) && !empty($event['Event']['Attribute'])) {
foreach ($event['Event']['Attribute'] as $key => $a) {
switch ($a['distribution']) {
case '1':
$event['Event']['Attribute'][$key]['distribution'] = '0';
break;
case '2':
$event['Event']['Attribute'][$key]['distribution'] = '1';
break;
}
}
}
}
// Distribution, set reporter of the event, being the admin that initiated the pull
$event['Event']['user_id'] = $user['id'];
// check if the event already exist (using the uuid)
$existingEvent = null;
$existingEvent = $eventModel->find('first', array('conditions' => array('Event.uuid' => $event['Event']['uuid'])));
if (!$existingEvent) {
// add data for newly imported events
$passAlong = $server['Server']['id'];
$result = $eventModel->_add($event, true, $user, $server['Server']['org_id'], $passAlong, true, $jobId);
if ($result) {
$successes[] = $eventId;
} else {
$fails[$eventId] = 'Failed (partially?) because of validation errors: '. json_encode($eventModel->validationErrors, true);
}
} else {
$tempUser = $user;
$tempUser['Role']['perm_site_admin'] = 0;
$result = $eventModel->_edit($event, $tempUser, $existingEvent['Event']['id'], $jobId);
if ($result === true) {
$successes[] = $eventId;
} elseif (isset($result['error'])) {
$fails[$eventId] = $result['error'];
} else {
$fails[$eventId] = json_encode($result);
}
}
} else {
// error
$fails[$eventId] = 'failed downloading the event';
}
if ($jobId) {
if ($k % 10 == 0) {
$job->id = $jobId;
$job->saveField('progress', 50 * (($k + 1) / count($eventIds)));
}
}
}
if (count($fails) > 0) {
// there are fails, take the lowest fail
$lastpulledid = min(array_keys($fails));
} else {
// no fails, take the highest success
$lastpulledid = count($successes) > 0 ? max($successes) : 0;
}
$HttpSocket = $this->setupHttpSocket($server);
foreach ($eventIds as $k => $eventId) {
$this->__pullEvents($eventId, $successes, $fails, $eventModel, $server, $user, $passAlong, $job, $jobId);
}
}
if ($jobId) {
@ -1961,58 +2033,9 @@ class Server extends AppModel
'recursive' => -1,
'conditions' => $conditions
));
$shadowAttribute = ClassRegistry::init('ShadowAttribute');
$shadowAttribute->recursive = -1;
if (!empty($events)) {
$proposals = $eventModel->downloadProposalsFromServer($events, $server);
if (!empty($proposals)) {
$uuidEvents = array_flip($events);
foreach ($proposals as $k => &$proposal) {
$proposal = $proposal['ShadowAttribute'];
$oldsa = $shadowAttribute->findOldProposal($proposal);
$proposal['event_id'] = $uuidEvents[$proposal['event_uuid']];
if (!$oldsa || $oldsa['timestamp'] < $proposal['timestamp']) {
if ($oldsa) {
$shadowAttribute->delete($oldsa['id']);
}
if (!isset($pulledProposals[$proposal['event_id']])) {
$pulledProposals[$proposal['event_id']] = 0;
}
$pulledProposals[$proposal['event_id']]++;
if (isset($proposal['old_id'])) {
$oldAttribute = $eventModel->Attribute->find('first', array('recursive' => -1, 'conditions' => array('uuid' => $proposal['uuid'])));
if ($oldAttribute) {
$proposal['old_id'] = $oldAttribute['Attribute']['id'];
} else {
$proposal['old_id'] = 0;
}
}
// check if this is a proposal from an old MISP instance
if (!isset($proposal['Org']) && isset($proposal['org']) && !empty($proposal['org'])) {
$proposal['Org'] = $proposal['org'];
$proposal['EventOrg'] = $proposal['event_org'];
} elseif (!isset($proposal['Org']) && !isset($proposal['EventOrg'])) {
continue;
}
$proposal['org_id'] = $this->Organisation->captureOrg($proposal['Org'], $user);
$proposal['event_org_id'] = $this->Organisation->captureOrg($proposal['EventOrg'], $user);
unset($proposal['Org']);
unset($proposal['EventOrg']);
$shadowAttribute->create();
if (!isset($proposal['deleted']) || !$proposal['deleted']) {
if ($shadowAttribute->save($proposal)) {
$shadowAttribute->sendProposalAlertEmail($proposal['event_id']);
}
}
}
if ($jobId) {
if ($k % 50 == 0) {
$job->id = $jobId;
$job->saveField('progress', 50 * (($k + 1) / count($proposals)));
}
}
}
}
$pulledProposals = $this->__handlePulledProposals($proposals, $events, $job, $jobId);
}
if ($jobId) {
$job->saveField('progress', 100);
@ -2029,12 +2052,9 @@ class Server extends AppModel
'action' => 'pull',
'user_id' => $user['id'],
'title' => 'Pull from ' . $server['Server']['url'] . ' initiated by ' . $email,
'change' => count($successes) . ' events and ' . count($pulledProposals) . ' proposals pulled or updated. ' . count($fails) . ' events failed or didn\'t need an update.'
'change' => count($successes) . ' events and ' . array_sum($pulledProposals) . ' proposals pulled or updated. ' . count($fails) . ' events failed or didn\'t need an update.'
));
if (!isset($lastpulledid)) {
$lastpulledid = 0;
}
return array($successes, $fails, $pulledProposals, $lastpulledid);
return array($successes, $fails, $pulledProposals);
}
public function filterRuleToParameter($filter_rules)

View File

@ -195,23 +195,41 @@ class Tag extends AppModel
public function findTagIdsByTagNames($array)
{
$ids = array();
foreach ($array as $a) {
$conditions['OR'][] = array('LOWER(Tag.name) like' => strtolower($a));
$tag_ids = array();
if (!is_array($array)) {
$array = array($array);
}
$params = array(
'recursive' => 1,
'conditions' => $conditions,
'fields' => array('Tag.id', 'Tag.id')
);
$result = $this->find('list', $params);
return array_values($result);
foreach ($array as $k => $tag) {
if (is_numeric($tag)) {
$tag_ids[] = $tag;
unset($array[$k]);
}
}
$array = array_values($array);
if (!empty($array)) {
foreach ($array as $a) {
$conditions['OR'][] = array('LOWER(Tag.name) like' => strtolower($a));
}
$params = array(
'recursive' => 1,
'conditions' => $conditions,
'fields' => array('Tag.id', 'Tag.id')
);
$result = $this->find('list', $params);
$tag_ids = array_merge($result, $tag_ids);
}
return array_values($tag_ids);
}
public function findEventIdsByTagNames($array)
{
$ids = array();
foreach ($array as $a) {
$conditions['OR'][] = array('LOWER(name) like' => strtolower($a));
if (is_numeric($a)) {
$conditions['OR'][] = array('id' => $a);
} else {
$conditions['OR'][] = array('LOWER(name) like' => strtolower($a));
}
}
$params = array(
'recursive' => 1,

View File

@ -26,6 +26,9 @@ class TaxonomyEntry extends AppModel
public function beforeValidate($options = array())
{
if (empty($this->data['TaxonomyEntry']['expanded'])) {
$this->data['TaxonomyEntry']['expanded'] = $this->data['TaxonomyEntry']['value'];
}
parent::beforeValidate();
return true;
}

View File

@ -28,6 +28,9 @@ class TaxonomyPredicate extends AppModel
public function beforeValidate($options = array())
{
if (empty($this->data['TaxonomyPredicate']['expanded'])) {
$this->data['TaxonomyPredicate']['expanded'] = $this->data['TaxonomyPredicate']['value'];
}
parent::beforeValidate();
return true;
}

View File

@ -529,7 +529,8 @@ class User extends AppModel
return $results;
}
private function testSmimeCertificate($certif_public) {
private function testSmimeCertificate($certif_public)
{
$result = array();
try {
App::uses('Folder', 'Utility');

View File

@ -17,6 +17,8 @@ class Whitelist extends AppModel
),
);
public $whitelistedItems = false;
public $validate = array(
'name' => array(
'valueNotEmpty' => array(
@ -66,12 +68,14 @@ class Whitelist extends AppModel
public function getBlockedValues()
{
$Whitelists = $this->find('all', array('fields' => array('name')));
$toReturn = array();
foreach ($Whitelists as $item) {
$toReturn[] = $item['Whitelist']['name'];
}
return $toReturn;
if ($this->whitelistedItems !== false) {
$Whitelists = $this->find('all', array('fields' => array('name')));
$this->whitelistedItems = array();
foreach ($Whitelists as $item) {
$this->whitelistedItems[] = $item['Whitelist']['name'];
}
}
return $this->whitelistedItems;
}
public function removeWhitelistedFromArray($data, $isAttributeArray)

View File

@ -170,7 +170,7 @@
<dd><?php echo h($attribute_count);?></dd>
<dt><?php echo __('Last change');?></dt>
<dd>
<?php echo date('Y/m/d h:i:s', $event['Event']['timestamp']);; ?>
<?php echo date('Y-m-d H:i:s', $event['Event']['timestamp']);; ?>
&nbsp;
</dd>
<dt><?php echo __('Extends');?></dt>

View File

@ -0,0 +1,20 @@
<div class="dashboard_element">
<?php
if (!empty($api_info['api_info'])) {
echo '<h4 class="blue bold">API info</h4>';
foreach ($api_info['api_info'] as $key => $value) {
if (!empty($value)) {
if (is_array($value)) {
foreach ($value as $k => $v) {
$value[$k] = h($v);
}
$value = implode('<br />', $value);
} else {
$value = h($value);
}
echo sprintf('<span class=blue>%s</span>:<br /><div style="padding-left:10px;">%s</div>', ucfirst(h($key)), $value);
}
}
}
?>
</div>

View File

@ -2,6 +2,7 @@
<?php echo $this->Form->create('Server');?>
<fieldset>
<legend><?php echo __('REST client');?></legend>
<div style="position:absolute;right:40px;width:300px;" id="apiInfo"></div>
<?php
echo $this->Form->input('method', array(
'label' => __('Relative path to query'),
@ -23,6 +24,10 @@
echo $this->Form->input('show_result', array(
'type' => 'checkbox'
));
echo $this->Form->input('skip_ssl_validation', array(
'type' => 'checkbox',
'label' => 'Skip SSL validation'
));
?>
<div class="input clear" style="width:100%;">
<?php
@ -47,20 +52,78 @@
echo $this->Form->end();
?>
<hr />
</fieldset>
</fieldset>
<?php
if (!empty($data['data'])) {
$formats = array('Raw', 'JSON', 'HTML');
if (!empty($data['data'])):
echo sprintf('<h3>%s</h3>', __('Response'));
echo sprintf('<div><span class="bold">%s</span>: %d</div>', __('Response code'), h($data['code']));
echo sprintf('<div><span class="bold">%s</span>: %s</div>', __('Request duration'), h($data['duration']));
echo sprintf('<div class="bold">%s</div>', __('Headers'));
foreach ($data['headers'] as $header => $value) {
echo sprintf('&nbsp;&nbsp;<span class="bold">%s</span>: %s<br />', h($header), h($value));
if (is_array($value)) {
$value = implode(',', $value);
}
echo sprintf('&nbsp;&nbsp;<span class="bold">%s</span>: %s<br />', h($header), h($value));
}
$format_toggles = '';
foreach ($formats as $k => $format) {
$position = '';
if ($k == 0) {
$position = '-left';
}
if ($k == (count($formats) -1)) {
$position = '-right';
}
$format_toggles .= sprintf('<span class="btn btn-inverse qet toggle%s format-toggle-button" data-toggle-type="%s">%s</span>', $position, $format, $format);
}
echo sprintf('<pre>%s</pre>', h($data['data']));
}
echo sprintf('<div style="padding-bottom:24px;">%s</div>', $format_toggles);
echo sprintf('<div class="hidden" id="rest-response-hidden-container">%s</div>', h($data['data']));
echo '<div id="rest-response-container"></div>';
endif;
?>
</div>
<?php
echo $this->element('side_menu', array('menuList' => 'event-collection', 'menuItem' => 'rest'));
?>
<script type="text/javascript">
// tooltips
$(document).ready(function () {
insertRawRestResponse();
$('.format-toggle-button').bind('click', function() {
$('#rest-response-container').empty();
if ($(this).data('toggle-type') == 'Raw') {
insertRawRestResponse();
} else if ($(this).data('toggle-type') == 'HTML') {
insertHTMLRestResponse();
} else if ($(this).data('toggle-type') == 'JSON') {
insertJSONRestResponse();
}
});
var thread = null;
$('#ServerUrl').keyup(function() {
clearTimeout(thread);
var $this = $(this);
var payload = {
"url": $('#ServerUrl').val()
};
if (payload) {
thread = setTimeout(
function() {
$.ajax({
type: "POST",
url: '/servers/getApiInfo',
data: payload,
success:function (data, textStatus) {
$('#apiInfo').html(data);
}
});
},
1000
);
} else {
$('#apiInfo').empty();
}
});
});
</script>

@ -1 +1 @@
Subproject commit 7b07b513b3bd8c47f3ff3d777eb3a86f14fbabd2
Subproject commit 0acc41131daaedbfdb94c068607c06db6c5ce293

@ -1 +1 @@
Subproject commit 3036ec875c3f82d2284dff8b858d2d6474f8a175
Subproject commit e90b1ce4575c122d410f143d5205771614004d9f

View File

@ -183,7 +183,6 @@ class StixBuilder(object):
def generateEventPackage(self):
package_name = "{}:STIXPackage-{}".format(namespace[1], self.misp_event.uuid)
# timestamp = self.get_date_from_timestamp(int(str(self.misp_event.timestamp)))
timestamp = self.misp_event.timestamp
stix_package = STIXPackage(id_=package_name, timestamp=timestamp)
stix_package.version = "1.1.1"
@ -208,9 +207,7 @@ class StixBuilder(object):
encoding='utf8'))
def generate_stix_objects(self):
incident_id = "{}:incident-{}".format(namespace[1], self.misp_event.uuid)
incident = Incident(id_=incident_id, title=self.misp_event.info)
self.set_dates(incident, self.misp_event.date, self.misp_event.publish_timestamp)
incident = self.create_incident(namespace[1])
self.history = History()
threat_level_name = threat_level_mapping.get(str(self.misp_event.threat_level_id), None)
if threat_level_name:
@ -254,13 +251,16 @@ class StixBuilder(object):
# converts a date (YYYY-mm-dd) to the format used by stix
return datetime.datetime(date.year, date.month, date.day)
def set_dates(self, incident, date, published):
timestamp = published
def create_incident(self, org):
incident_id = "{}:incident-{}".format(org, self.misp_event.uuid)
incident = Incident(id_=incident_id, title=self.misp_event.info)
timestamp = self.misp_event.publish_timestamp
incident.timestamp = timestamp
incident_time = Time()
incident_time.incident_discovery = self.convert_to_stix_date(date)
incident_time.incident_discovery = self.convert_to_stix_date(self.misp_event.date)
incident_time.incident_reported = timestamp
incident.time = incident_time
return incident
def resolve_attributes(self, incident, tags):
for attribute in self.misp_event.attributes:
@ -355,7 +355,7 @@ class StixBuilder(object):
def create_indicator(self, misp_object, observable, tags):
tlp_tags = deepcopy(tags)
indicator = Indicator(timestamp=self.get_date_from_timestamp(int(misp_object.timestamp)))
indicator = Indicator(timestamp=misp_object.timestamp)
indicator.id_ = "{}:MISPObject-{}".format(namespace[1], misp_object.uuid)
indicator.producer = self.set_prod(self.orgc_name)
for attribute in misp_object.attributes:
@ -546,16 +546,10 @@ class StixBuilder(object):
regkey, value = attribute.value.split('|')
else:
regkey = attribute.value
reghive, regkey = self.resolve_reg_hive(regkey)
reg_object = WinRegistryKey()
reg_object.key = regkey
reg_object.key.condition = "Equals"
if reghive:
reg_object.hive = reghive
reg_object.hive.condition = "Equals"
reg_object = self.create_regkey_object(regkey)
if value:
reg_value_object = RegistryValue()
reg_value_object.data = value
reg_value_object.data = value.strip()
reg_value_object.data.condition = "Equals"
reg_object.values = RegistryValues(reg_value_object)
reg_object.parent.id_ = "{}:WinRegistryKeyObject-{}".format(self.namespace_prefix, attribute.uuid)
@ -921,16 +915,9 @@ class StixBuilder(object):
def parse_regkey_object(self, misp_object):
to_ids, attributes_dict = self.create_attributes_dict(misp_object.attributes)
reg_object = WinRegistryKey()
registry_values = False
reg_value_object = RegistryValue()
if 'key' in attributes_dict:
reghive, regkey = self.resolve_reg_hive(attributes_dict['key'])
reg_object.key = regkey
reg_object.key.condition = "Equals"
if reghive:
reg_object.hive = reghive
reg_object.hive.condition = "Equals"
reg_object = self.create_regkey_object(attributes_dict['key']) if 'key' in attributes_dict else WinRegistryKey()
if 'last-modified' in attributes_dict:
reg_object.modified_time = attributes_dict['last-modified']
reg_object.modified_time.condition = "Equals"
@ -939,7 +926,7 @@ class StixBuilder(object):
reg_value_object.name.condition = "Equals"
registry_values = True
if 'data' in attributes_dict:
reg_value_object.data = attributes_dict['data']
reg_value_object.data = attributes_dict['data'].strip()
reg_value_object.data.condition = "Equals"
registry_values = True
if 'data-type' in attributes_dict:
@ -1393,6 +1380,16 @@ class StixBuilder(object):
port_observable.id_ = "{}:{}Port-{}".format(self.namespace_prefix, port_type, uuid)
return port_observable
def create_regkey_object(self, regkey):
reghive, regkey = self.resolve_reg_hive(regkey)
reg_object = WinRegistryKey()
reg_object.key = regkey.strip()
reg_object.key.condition = "Equals"
if reghive:
reg_object.hive = reghive.strip()
reg_object.hive.condition = "Equals"
return reg_object
def create_socket_address_object(self, sao_type, **kwargs):
socket_address_object = SocketAddress()
ip_type, port_type, hostname_type = [arg.format(sao_type) for arg in ('ip-{}', '{}-port', 'hostname-{}')]
@ -1524,11 +1521,6 @@ class StixBuilder(object):
if key in hash_type_attributes['single']:
file_object.add_hash(Hash(hash_value=value, exact=True))
@staticmethod
def get_date_from_timestamp(timestamp):
# converts timestamp to the format used by STIX
return "{}+00:00".format(datetime.datetime.fromtimestamp(timestamp).isoformat())
@staticmethod
def fetch_colors(tags):
colors = []

View File

@ -68,7 +68,7 @@ class StixBuilder():
def eventReport(self):
report_args = {'type': 'report', 'id': self.report_id, 'name': self.misp_event.info,
'created_by_ref': self.identity_id, 'published': self.misp_event.publish_timestamp,
'object_refs': self.object_refs}
'created': self.misp_event.date, 'object_refs': self.object_refs}
if self.misp_event.Tag:
labels = []
for tag in self.misp_event.Tag:
@ -463,7 +463,7 @@ class StixBuilder():
attribute_value = attribute.value if attribute_type != "AS" else self.define_attribute_value(attribute.value, attribute.comment)
pattern = mispTypesMapping[attribute_type]['pattern'](attribute_type, attribute_value, b64encode(attribute.data.getbuffer()).decode()[1:-1]) if ('data' in attribute and attribute.data) else self.define_pattern(attribute_type, attribute_value)
indicator_args = {'id': indicator_id, 'type': 'indicator', 'labels': labels, 'kill_chain_phases': killchain,
'valid_from': attribute.timestamp, 'created_by_ref': self.identity_id, 'pattern': pattern}
'valid_from': self.misp_event.date, 'created_by_ref': self.identity_id, 'pattern': pattern}
if hasattr(attribute, 'comment') and attribute.comment:
indicator_args['description'] = attribute.comment
indicator = Indicator(**indicator_args)
@ -542,10 +542,9 @@ class StixBuilder():
category = misp_object.get('meta-category')
labels = self.create_object_labels(name, category, to_ids)
values = self.fetch_custom_values(misp_object.attributes, custom_object_id)
timestamp = self.get_date_from_timestamp(int(misp_object.timestamp))
custom_object_args = {'id': custom_object_id, 'x_misp_values': values, 'labels': labels,
'x_misp_category': category, 'created_by_ref': self.identity_id,
'x_misp_timestamp': timestamp}
'x_misp_timestamp': misp_object.timestamp}
if hasattr(misp_object, 'comment') and misp_object.comment:
custom_object_args['x_misp_comment'] = misp_object.comment
@CustomObject(custom_object_type, [('id', properties.StringProperty(required=True)),
@ -573,8 +572,7 @@ class StixBuilder():
category = misp_object.get('meta-category')
killchain = self.create_killchain(category)
labels = self.create_object_labels(name, category, True)
timestamp = self.get_date_from_timestamp(int(misp_object.timestamp))
indicator_args = {'id': indicator_id, 'valid_from': timestamp, 'type': 'indicator',
indicator_args = {'id': indicator_id, 'valid_from': self.misp_event.date, 'type': 'indicator',
'labels': labels, 'description': misp_object.description,
'pattern': pattern, 'kill_chain_phases': killchain,
'created_by_ref': self.identity_id}
@ -591,7 +589,7 @@ class StixBuilder():
observable_objects = self.objects_mapping[name]['observable'](misp_object.attributes, observed_data_id)
category = misp_object.get('meta-category')
labels = self.create_object_labels(name, category, False)
timestamp = self.get_date_from_timestamp(int(misp_object.timestamp))
timestamp = misp_object.timestamp
observed_data_args = {'id': observed_data_id, 'type': 'observed-data',
'number_observed': 1, 'labels': labels, 'objects': observable_objects,
'first_observed': timestamp, 'last_observed': timestamp,
@ -695,10 +693,6 @@ class StixBuilder():
return attribute.value
return "Undefined name"
@staticmethod
def get_date_from_timestamp(timestamp):
return datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=timestamp)
def resolve_asn_observable(self, attributes, object_id):
asn = objectsMapping['asn']['observable']
observable = {}

View File

@ -249,10 +249,10 @@ class StixParser():
try:
try:
dt = date.split('+')[0]
d = int(time.mktime(time.strptime(dt, "%Y-%m-%dT%H:%M:%S")))
d = int(time.mktime(time.strptime(dt, "%Y-%m-%d %H:%M:%S")))
except ValueError:
dt = date.split('.')[0]
d = int(time.mktime(time.strptime(dt, "%Y-%m-%dT%H:%M:%S")))
d = int(time.mktime(time.strptime(dt, "%Y-%m-%d %H:%M:%S")))
except AttributeError:
d = int(time.mktime(date.timetuple()))
return d
@ -607,6 +607,13 @@ class StixParser():
values = properties.values
value = values[0]
attributes += self.fetch_attributes_with_partial_key_parsing(value, stix2misp_mapping._regkey_value_mapping)
if len(attributes) in (2,3):
d_regkey = {key: value for (_, value, key) in attributes}
if 'hive' in d_regkey and 'key' in d_regkey:
regkey = "{}\\{}".format(d_regkey['hive'], d_regkey['key'])
if 'data' in d_regkey:
return "regkey|value", "{} | {}".format(regkey, d_regkey['data']), ""
return "regkey", regkey, ""
return "registry-key", self.return_attributes(attributes), ""
@staticmethod

@ -1 +1 @@
Subproject commit 91d08ccf060ca18bbbeae3d8645d4446be5ddcf0
Subproject commit b7ebd32485963c410b4274f8051f3236325c4b2f

View File

@ -1559,6 +1559,19 @@ a.proposal_link_red:hover {
color: white;
}
.json_key {
color: #690;
font-weight: bold;
}
.json_string, .json_boolean, .json_number {
color: #905;
}
.json_null {
color: #a8a8a8;
}
.background-lightblue {
background-color:#cfefff;
}

View File

@ -3431,6 +3431,46 @@ function checkIfLoggedIn() {
setTimeout(function() { checkIfLoggedIn(); }, 5000);
}
function insertRawRestResponse() {
$('#rest-response-container').append('<pre id="raw-response-container" />');
$('#raw-response-container').text($('#rest-response-hidden-container').text());
}
function insertHTMLRestResponse() {
$('#rest-response-container').append('<div id="html-response-container" style="border: 1px solid blue; padding:5px;" />');
$('#html-response-container').html($('#rest-response-hidden-container').text());
}
function insertJSONRestResponse() {
$('#rest-response-container').append('<p id="json-response-container" style="border: 1px solid blue; padding:5px;" />');
var parsedJson = syntaxHighlightJson($('#rest-response-hidden-container').text());
console.log(parsedJson);
$('#json-response-container').html(parsedJson);
}
function syntaxHighlightJson(json) {
if (typeof json == 'string') {
json = JSON.parse(json);
}
json = JSON.stringify(json, undefined, 2);
json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/(?:\r\n|\r|\n)/g, '<br>').replace(/ /g, '&nbsp;');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var cls = 'json_number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'json_key';
} else {
cls = 'json_string';
}
} else if (/true|false/.test(match)) {
cls = 'json_boolean';
} else if (/null/.test(match)) {
cls = 'json_null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
(function(){
"use strict";
$(".datepicker").datepicker({

View File

@ -1,31 +1,68 @@
uuid,event_id,category,type,value,comment,to_ids,date,object_relation,object_uuid,object_name,object_meta_category
"548847d8-01e0-4231-a739-15bb950d210b",750,"Payload installation","md5","744c07e886497f7b68f6f7fe57b7ab54","Regin samples collected.",1,20141210,"","","",""
"548847d8-05f8-49e7-af79-15bb950d210b",750,"Payload installation","md5","47d0e8f9d7a6429920329207a32ecc2e","Regin samples collected.",1,20141210,"","","",""
"548847d8-3fbc-4a06-ba82-15bb950d210b",750,"Payload installation","md5","2c8b9d2885543d7ade3cae98225e263b","Regin samples collected.",1,20141210,"","","",""
"548847d8-9db0-4df6-8206-15bb950d210b",750,"Payload installation","md5","26297dc3cd0b688de3b846983c5385e5","Regin samples collected.",1,20141210,"","","",""
"548847d8-a33c-41f3-9f7a-15bb950d210b",750,"Payload installation","md5","01c2f321b6bfdb9473c079b0797567ba","Regin samples collected.",1,20141210,"","","",""
"548847d8-c950-48eb-b960-15bb950d210b",750,"Payload installation","md5","4b6b86c7fec1c574706cecedf44abded","Regin samples collected.",1,20141210,"","","",""
"548847d9-1404-4331-ae3c-15bb950d210b",750,"Payload installation","md5","90fecc6a89b2e22d82d58878d93477d4","Regin samples collected.",1,20141210,"","","",""
"548847d9-39dc-4247-b23d-15bb950d210b",750,"Payload installation","md5","06665b96e293b23acc80451abb413e50","Regin samples collected.",1,20141210,"","","",""
"548847d9-3b28-449e-b527-15bb950d210b",750,"Payload installation","md5","e94393561901895cb0783edc34740fd4","Regin samples collected.",1,20141210,"","","",""
"548847d9-4020-41da-b5f3-15bb950d210b",750,"Payload installation","md5","db405ad775ac887a337b02ea8b07fddc","Regin samples collected.",1,20141210,"","","",""
"548847d9-6340-44a0-8f33-15bb950d210b",750,"Payload installation","md5","ffb0b9b5b610191051a7bdf0806e1e47","Regin samples collected.",1,20141210,"","","",""
"548847d9-8b18-4654-9766-15bb950d210b",750,"Payload installation","md5","f3ffc2aaaa1e2ab55ec26ff098653347","Regin samples collected.",1,20141210,"","","",""
"548847d9-a564-4178-b8e6-15bb950d210b",750,"Payload installation","md5","6662c390b2bbbd291ec7987388fc75d7","Regin samples collected.",1,20141210,"","","",""
"548847d9-afe0-4531-a4b0-15bb950d210b",750,"Payload installation","md5","187044596bc1328efa0ed636d8aa4a5c","Regin samples collected.",1,20141210,"","","",""
"548847d9-b63c-4c95-a2bd-15bb950d210b",750,"Payload installation","md5","1800def71006ca6790767e202fae9b9a","Regin samples collected.",1,20141210,"","","",""
"548847d9-e6fc-4b93-a773-15bb950d210b",750,"Payload installation","md5","bfbe8c3ee78750c3a520480700e440f8","Regin samples collected.",1,20141210,"","","",""
"548847d9-fd54-4e49-909b-15bb950d210b",750,"Payload installation","md5","89003e9a1ae635c97ebad07aebc67f00","Regin samples collected.",1,20141210,"","","",""
"548847da-1660-4562-a1f8-15bb950d210b",750,"Payload installation","md5","b505d65721bb2453d5039a389113b566","Regin samples collected.",1,20141210,"","","",""
"548847da-2134-43d7-ba22-15bb950d210b",750,"Payload installation","md5","8fcf4e53ece6111758a1dd3139dc7cad","Regin samples collected.",1,20141210,"","","",""
"548847da-3e40-4ab2-a5eb-15bb950d210b",750,"Payload installation","md5","1c024e599ac055312a4ab75b3950040a","Regin samples collected.",1,20141210,"","","",""
"548847da-49c0-404d-ae42-15bb950d210b",750,"Payload installation","md5","d240f06e98c8d3e647cbf4d442d79475","Regin samples collected.",1,20141210,"","","",""
"548847da-71ec-4b2b-bae5-15bb950d210b",750,"Payload installation","md5","148c1bb9d405d717252c77593aff4bd8","Regin samples collected.",1,20141210,"","","",""
"548847da-9798-4b6d-b422-15bb950d210b",750,"Payload installation","md5","ba7bb65634ce1e30c1e5415be3d1db1d","Regin samples collected.",1,20141210,"","","",""
"548847da-ac78-474c-86fe-15bb950d210b",750,"Payload installation","md5","b29ca4f22ae7b7b25f79c1d4a421139d","Regin samples collected.",1,20141210,"","","",""
"548847da-c2d0-4d24-821e-15bb950d210b",750,"Payload installation","md5","b269894f434657db2b15949641a67532","Regin samples collected.",1,20141210,"","","",""
"548847da-ffe4-4a90-9f2a-15bb950d210b",750,"Payload installation","md5","22bfc970f707fd775d49e875b63c2f0c","Regin samples collected.",1,20141210,"","","",""
"548847db-060c-4275-a0c7-15bb950d210b",750,"Payload installation","md5","049436bb90f71cf38549817d9b90e2da","Regin samples collected.",1,20141210,"","","",""
"5488486c-1418-4624-b87c-15ba950d210b",750,"Artifacts dropped","regkey","Class\{4F20E605-9452-4787-B793-D0204917CA58}","",1,20141210,"","","",""
"5488486c-47ec-4952-8e60-15ba950d210b",750,"Artifacts dropped","regkey","Class\{9B9A8ADB-8864-4BC4-8AD5-B17DFDBB9F58}","",1,20141210,"","","",""
"5488486c-a044-4c31-830c-15ba950d210b",750,"Artifacts dropped","regkey","HKLM\System\CurrentControlSet\Control\","",1,20141210,"","","",""
"5488466a-f0d0-4b58-89a5-15bc950d210b",1635,"External analysis","link","https://www.f-secure.com/documents/996508/1030745/w32_regin_stage_1.pdf","",,20141210,"","","",""
"548847d8-01e0-4231-a739-15bb950d210b",1635,"Payload installation","md5","744c07e886497f7b68f6f7fe57b7ab54","Regin samples collected.",1,20141210,"","","",""
"548847d8-05f8-49e7-af79-15bb950d210b",1635,"Payload installation","md5","47d0e8f9d7a6429920329207a32ecc2e","Regin samples collected.",1,20141210,"","","",""
"548847d8-3fbc-4a06-ba82-15bb950d210b",1635,"Payload installation","md5","2c8b9d2885543d7ade3cae98225e263b","Regin samples collected.",1,20141210,"","","",""
"548847d8-9db0-4df6-8206-15bb950d210b",1635,"Payload installation","md5","26297dc3cd0b688de3b846983c5385e5","Regin samples collected.",1,20141210,"","","",""
"548847d8-a33c-41f3-9f7a-15bb950d210b",1635,"Payload installation","md5","01c2f321b6bfdb9473c079b0797567ba","Regin samples collected.",1,20141210,"","","",""
"548847d8-c950-48eb-b960-15bb950d210b",1635,"Payload installation","md5","4b6b86c7fec1c574706cecedf44abded","Regin samples collected.",1,20141210,"","","",""
"548847d9-1404-4331-ae3c-15bb950d210b",1635,"Payload installation","md5","90fecc6a89b2e22d82d58878d93477d4","Regin samples collected.",1,20141210,"","","",""
"548847d9-39dc-4247-b23d-15bb950d210b",1635,"Payload installation","md5","06665b96e293b23acc80451abb413e50","Regin samples collected.",1,20141210,"","","",""
"548847d9-3b28-449e-b527-15bb950d210b",1635,"Payload installation","md5","e94393561901895cb0783edc34740fd4","Regin samples collected.",1,20141210,"","","",""
"548847d9-4020-41da-b5f3-15bb950d210b",1635,"Payload installation","md5","db405ad775ac887a337b02ea8b07fddc","Regin samples collected.",1,20141210,"","","",""
"548847d9-6340-44a0-8f33-15bb950d210b",1635,"Payload installation","md5","ffb0b9b5b610191051a7bdf0806e1e47","Regin samples collected.",1,20141210,"","","",""
"548847d9-8b18-4654-9766-15bb950d210b",1635,"Payload installation","md5","f3ffc2aaaa1e2ab55ec26ff098653347","Regin samples collected.",1,20141210,"","","",""
"548847d9-a564-4178-b8e6-15bb950d210b",1635,"Payload installation","md5","6662c390b2bbbd291ec7987388fc75d7","Regin samples collected.",1,20141210,"","","",""
"548847d9-afe0-4531-a4b0-15bb950d210b",1635,"Payload installation","md5","187044596bc1328efa0ed636d8aa4a5c","Regin samples collected.",1,20141210,"","","",""
"548847d9-b63c-4c95-a2bd-15bb950d210b",1635,"Payload installation","md5","1800def71006ca6790767e202fae9b9a","Regin samples collected.",1,20141210,"","","",""
"548847d9-e6fc-4b93-a773-15bb950d210b",1635,"Payload installation","md5","bfbe8c3ee78750c3a520480700e440f8","Regin samples collected.",1,20141210,"","","",""
"548847d9-fd54-4e49-909b-15bb950d210b",1635,"Payload installation","md5","89003e9a1ae635c97ebad07aebc67f00","Regin samples collected.",1,20141210,"","","",""
"548847da-1660-4562-a1f8-15bb950d210b",1635,"Payload installation","md5","b505d65721bb2453d5039a389113b566","Regin samples collected.",1,20141210,"","","",""
"548847da-2134-43d7-ba22-15bb950d210b",1635,"Payload installation","md5","8fcf4e53ece6111758a1dd3139dc7cad","Regin samples collected.",1,20141210,"","","",""
"548847da-3e40-4ab2-a5eb-15bb950d210b",1635,"Payload installation","md5","1c024e599ac055312a4ab75b3950040a","Regin samples collected.",1,20141210,"","","",""
"548847da-49c0-404d-ae42-15bb950d210b",1635,"Payload installation","md5","d240f06e98c8d3e647cbf4d442d79475","Regin samples collected.",1,20141210,"","","",""
"548847da-71ec-4b2b-bae5-15bb950d210b",1635,"Payload installation","md5","148c1bb9d405d717252c77593aff4bd8","Regin samples collected.",1,20141210,"","","",""
"548847da-9798-4b6d-b422-15bb950d210b",1635,"Payload installation","md5","ba7bb65634ce1e30c1e5415be3d1db1d","Regin samples collected.",1,20141210,"","","",""
"548847da-ac78-474c-86fe-15bb950d210b",1635,"Payload installation","md5","b29ca4f22ae7b7b25f79c1d4a421139d","Regin samples collected.",1,20141210,"","","",""
"548847da-c2d0-4d24-821e-15bb950d210b",1635,"Payload installation","md5","b269894f434657db2b15949641a67532","Regin samples collected.",1,20141210,"","","",""
"548847da-ffe4-4a90-9f2a-15bb950d210b",1635,"Payload installation","md5","22bfc970f707fd775d49e875b63c2f0c","Regin samples collected.",1,20141210,"","","",""
"548847db-060c-4275-a0c7-15bb950d210b",1635,"Payload installation","md5","049436bb90f71cf38549817d9b90e2da","Regin samples collected.",1,20141210,"","","",""
"54884832-2608-4fe6-959e-1ac6950d210b",1635,"Artifacts dropped","filename","ser8uart.sys","",,20141210,"","","",""
"54884832-5134-460e-bea2-1ac6950d210b",1635,"Artifacts dropped","filename","atdisk.sys","",,20141210,"","","",""
"54884832-6fb4-4c63-937c-1ac6950d210b",1635,"Artifacts dropped","filename","rdpmdd.sys","",,20141210,"","","",""
"54884832-93a4-4fb0-aeba-1ac6950d210b",1635,"Artifacts dropped","filename","usbclass.sys","",,20141210,"","","",""
"54884832-983c-4e4c-a692-1ac6950d210b",1635,"Artifacts dropped","filename","pcidump.sys","",,20141210,"","","",""
"54884832-f2a8-46ff-be58-1ac6950d210b",1635,"Artifacts dropped","filename","abiosdsk.sys","",,20141210,"","","",""
"5488486c-1418-4624-b87c-15ba950d210b",1635,"Artifacts dropped","regkey","Class\{4F20E605-9452-4787-B793-D0204917CA58}","",1,20141210,"","","",""
"5488486c-47ec-4952-8e60-15ba950d210b",1635,"Artifacts dropped","regkey","Class\{9B9A8ADB-8864-4BC4-8AD5-B17DFDBB9F58}","",1,20141210,"","","",""
"5488486c-a044-4c31-830c-15ba950d210b",1635,"Artifacts dropped","regkey","HKLM\System\CurrentControlSet\Control\","",1,20141210,"","","",""
"5488488d-a4ec-4b40-bd7d-15c7950d210b",1635,"External analysis","text","In this document we analyze a set of 32-bit samples
which represents stage #1 of the complex threat that is
known as Regin. Based on our analysis of the malwares
functionalities, this part of the Regin threat can be
considered just a support module — its sole purpose
is to facilitate and enable the operations of stage #2
by loading it and making it more difficult to detect by
security products.
Regins stage #1 targets the Windows platform and
support various versions of the operating system,
beginning with Windows NT 4.0. Based on our analysis,
the samples may be classified into two categories: “pure”
samples that do not feature any extra, non-malicious
code; and “augmented” ones which feature malware
code as part of another device driver. The existence of
“augmented” samples indicates the intention of the
attacker to remain undiscovered for as long as possible.
When activated, samples of Regin stage #1 will
retrieve encrypted content from specific locations of
an already compromised system, map it into kernel
memory and transfer control to it. In terms of technical
sophistication, stage #1s import resolution process is
of particular interest, as the malware uses the unusual
“trampoline” technique to mask the payloads access to
API functions.
It is clear that this support component, that represents
the initial stage of a very complex threat, has been
instrumental in securing long-term persistence in the
attacks that made use of this threat.","",,20141210,"","","",""
"54884899-35b8-48a3-9da2-15c6950d210b",1635,"Other","text","Regin","",,20141210,"","","",""

1 uuid event_id category type value comment to_ids date object_relation object_uuid object_name object_meta_category
2 548847d8-01e0-4231-a739-15bb950d210b 5488466a-f0d0-4b58-89a5-15bc950d210b 750 1635 Payload installation External analysis md5 link 744c07e886497f7b68f6f7fe57b7ab54 https://www.f-secure.com/documents/996508/1030745/w32_regin_stage_1.pdf Regin samples collected. 1 20141210
3 548847d8-05f8-49e7-af79-15bb950d210b 548847d8-01e0-4231-a739-15bb950d210b 750 1635 Payload installation md5 47d0e8f9d7a6429920329207a32ecc2e 744c07e886497f7b68f6f7fe57b7ab54 Regin samples collected. 1 20141210
4 548847d8-3fbc-4a06-ba82-15bb950d210b 548847d8-05f8-49e7-af79-15bb950d210b 750 1635 Payload installation md5 2c8b9d2885543d7ade3cae98225e263b 47d0e8f9d7a6429920329207a32ecc2e Regin samples collected. 1 20141210
5 548847d8-9db0-4df6-8206-15bb950d210b 548847d8-3fbc-4a06-ba82-15bb950d210b 750 1635 Payload installation md5 26297dc3cd0b688de3b846983c5385e5 2c8b9d2885543d7ade3cae98225e263b Regin samples collected. 1 20141210
6 548847d8-a33c-41f3-9f7a-15bb950d210b 548847d8-9db0-4df6-8206-15bb950d210b 750 1635 Payload installation md5 01c2f321b6bfdb9473c079b0797567ba 26297dc3cd0b688de3b846983c5385e5 Regin samples collected. 1 20141210
7 548847d8-c950-48eb-b960-15bb950d210b 548847d8-a33c-41f3-9f7a-15bb950d210b 750 1635 Payload installation md5 4b6b86c7fec1c574706cecedf44abded 01c2f321b6bfdb9473c079b0797567ba Regin samples collected. 1 20141210
8 548847d9-1404-4331-ae3c-15bb950d210b 548847d8-c950-48eb-b960-15bb950d210b 750 1635 Payload installation md5 90fecc6a89b2e22d82d58878d93477d4 4b6b86c7fec1c574706cecedf44abded Regin samples collected. 1 20141210
9 548847d9-39dc-4247-b23d-15bb950d210b 548847d9-1404-4331-ae3c-15bb950d210b 750 1635 Payload installation md5 06665b96e293b23acc80451abb413e50 90fecc6a89b2e22d82d58878d93477d4 Regin samples collected. 1 20141210
10 548847d9-3b28-449e-b527-15bb950d210b 548847d9-39dc-4247-b23d-15bb950d210b 750 1635 Payload installation md5 e94393561901895cb0783edc34740fd4 06665b96e293b23acc80451abb413e50 Regin samples collected. 1 20141210
11 548847d9-4020-41da-b5f3-15bb950d210b 548847d9-3b28-449e-b527-15bb950d210b 750 1635 Payload installation md5 db405ad775ac887a337b02ea8b07fddc e94393561901895cb0783edc34740fd4 Regin samples collected. 1 20141210
12 548847d9-6340-44a0-8f33-15bb950d210b 548847d9-4020-41da-b5f3-15bb950d210b 750 1635 Payload installation md5 ffb0b9b5b610191051a7bdf0806e1e47 db405ad775ac887a337b02ea8b07fddc Regin samples collected. 1 20141210
13 548847d9-8b18-4654-9766-15bb950d210b 548847d9-6340-44a0-8f33-15bb950d210b 750 1635 Payload installation md5 f3ffc2aaaa1e2ab55ec26ff098653347 ffb0b9b5b610191051a7bdf0806e1e47 Regin samples collected. 1 20141210
14 548847d9-a564-4178-b8e6-15bb950d210b 548847d9-8b18-4654-9766-15bb950d210b 750 1635 Payload installation md5 6662c390b2bbbd291ec7987388fc75d7 f3ffc2aaaa1e2ab55ec26ff098653347 Regin samples collected. 1 20141210
15 548847d9-afe0-4531-a4b0-15bb950d210b 548847d9-a564-4178-b8e6-15bb950d210b 750 1635 Payload installation md5 187044596bc1328efa0ed636d8aa4a5c 6662c390b2bbbd291ec7987388fc75d7 Regin samples collected. 1 20141210
16 548847d9-b63c-4c95-a2bd-15bb950d210b 548847d9-afe0-4531-a4b0-15bb950d210b 750 1635 Payload installation md5 1800def71006ca6790767e202fae9b9a 187044596bc1328efa0ed636d8aa4a5c Regin samples collected. 1 20141210
17 548847d9-e6fc-4b93-a773-15bb950d210b 548847d9-b63c-4c95-a2bd-15bb950d210b 750 1635 Payload installation md5 bfbe8c3ee78750c3a520480700e440f8 1800def71006ca6790767e202fae9b9a Regin samples collected. 1 20141210
18 548847d9-fd54-4e49-909b-15bb950d210b 548847d9-e6fc-4b93-a773-15bb950d210b 750 1635 Payload installation md5 89003e9a1ae635c97ebad07aebc67f00 bfbe8c3ee78750c3a520480700e440f8 Regin samples collected. 1 20141210
19 548847da-1660-4562-a1f8-15bb950d210b 548847d9-fd54-4e49-909b-15bb950d210b 750 1635 Payload installation md5 b505d65721bb2453d5039a389113b566 89003e9a1ae635c97ebad07aebc67f00 Regin samples collected. 1 20141210
20 548847da-2134-43d7-ba22-15bb950d210b 548847da-1660-4562-a1f8-15bb950d210b 750 1635 Payload installation md5 8fcf4e53ece6111758a1dd3139dc7cad b505d65721bb2453d5039a389113b566 Regin samples collected. 1 20141210
21 548847da-3e40-4ab2-a5eb-15bb950d210b 548847da-2134-43d7-ba22-15bb950d210b 750 1635 Payload installation md5 1c024e599ac055312a4ab75b3950040a 8fcf4e53ece6111758a1dd3139dc7cad Regin samples collected. 1 20141210
22 548847da-49c0-404d-ae42-15bb950d210b 548847da-3e40-4ab2-a5eb-15bb950d210b 750 1635 Payload installation md5 d240f06e98c8d3e647cbf4d442d79475 1c024e599ac055312a4ab75b3950040a Regin samples collected. 1 20141210
23 548847da-71ec-4b2b-bae5-15bb950d210b 548847da-49c0-404d-ae42-15bb950d210b 750 1635 Payload installation md5 148c1bb9d405d717252c77593aff4bd8 d240f06e98c8d3e647cbf4d442d79475 Regin samples collected. 1 20141210
24 548847da-9798-4b6d-b422-15bb950d210b 548847da-71ec-4b2b-bae5-15bb950d210b 750 1635 Payload installation md5 ba7bb65634ce1e30c1e5415be3d1db1d 148c1bb9d405d717252c77593aff4bd8 Regin samples collected. 1 20141210
25 548847da-ac78-474c-86fe-15bb950d210b 548847da-9798-4b6d-b422-15bb950d210b 750 1635 Payload installation md5 b29ca4f22ae7b7b25f79c1d4a421139d ba7bb65634ce1e30c1e5415be3d1db1d Regin samples collected. 1 20141210
26 548847da-c2d0-4d24-821e-15bb950d210b 548847da-ac78-474c-86fe-15bb950d210b 750 1635 Payload installation md5 b269894f434657db2b15949641a67532 b29ca4f22ae7b7b25f79c1d4a421139d Regin samples collected. 1 20141210
27 548847da-ffe4-4a90-9f2a-15bb950d210b 548847da-c2d0-4d24-821e-15bb950d210b 750 1635 Payload installation md5 22bfc970f707fd775d49e875b63c2f0c b269894f434657db2b15949641a67532 Regin samples collected. 1 20141210
28 548847db-060c-4275-a0c7-15bb950d210b 548847da-ffe4-4a90-9f2a-15bb950d210b 750 1635 Payload installation md5 049436bb90f71cf38549817d9b90e2da 22bfc970f707fd775d49e875b63c2f0c Regin samples collected. 1 20141210
29 5488486c-1418-4624-b87c-15ba950d210b 548847db-060c-4275-a0c7-15bb950d210b 750 1635 Artifacts dropped Payload installation regkey md5 Class\{4F20E605-9452-4787-B793-D0204917CA58} 049436bb90f71cf38549817d9b90e2da Regin samples collected. 1 20141210
30 5488486c-47ec-4952-8e60-15ba950d210b 54884832-2608-4fe6-959e-1ac6950d210b 750 1635 Artifacts dropped regkey filename Class\{9B9A8ADB-8864-4BC4-8AD5-B17DFDBB9F58} ser8uart.sys 1 20141210
31 5488486c-a044-4c31-830c-15ba950d210b 54884832-5134-460e-bea2-1ac6950d210b 750 1635 Artifacts dropped regkey filename HKLM\System\CurrentControlSet\Control\ atdisk.sys 1 20141210
32 54884832-6fb4-4c63-937c-1ac6950d210b 1635 Artifacts dropped filename rdpmdd.sys 20141210
33 54884832-93a4-4fb0-aeba-1ac6950d210b 1635 Artifacts dropped filename usbclass.sys 20141210
34 54884832-983c-4e4c-a692-1ac6950d210b 1635 Artifacts dropped filename pcidump.sys 20141210
35 54884832-f2a8-46ff-be58-1ac6950d210b 1635 Artifacts dropped filename abiosdsk.sys 20141210
36 5488486c-1418-4624-b87c-15ba950d210b 1635 Artifacts dropped regkey Class\{4F20E605-9452-4787-B793-D0204917CA58} 1 20141210
37 5488486c-47ec-4952-8e60-15ba950d210b 1635 Artifacts dropped regkey Class\{9B9A8ADB-8864-4BC4-8AD5-B17DFDBB9F58} 1 20141210
38 5488486c-a044-4c31-830c-15ba950d210b 1635 Artifacts dropped regkey HKLM\System\CurrentControlSet\Control\ 1 20141210
39 5488488d-a4ec-4b40-bd7d-15c7950d210b 1635 External analysis text In this document we analyze a set of 32-bit samples which represents stage #1 of the complex threat that is known as Regin. Based on our analysis of the malware’s functionalities, this part of the Regin threat can be considered just a support module — its sole purpose is to facilitate and enable the operations of stage #2 by loading it and making it more difficult to detect by security products. Regin’s stage #1 targets the Windows platform and support various versions of the operating system, beginning with Windows NT 4.0. Based on our analysis, the samples may be classified into two categories: “pure” samples that do not feature any extra, non-malicious code; and “augmented” ones which feature malware code as part of another device driver. The existence of “augmented” samples indicates the intention of the attacker to remain undiscovered for as long as possible. When activated, samples of Regin stage #1 will retrieve encrypted content from specific locations of an already compromised system, map it into kernel memory and transfer control to it. In terms of technical sophistication, stage #1’s import resolution process is of particular interest, as the malware uses the unusual “trampoline” technique to mask the payload’s access to API functions. It is clear that this support component, that represents the initial stage of a very complex threat, has been instrumental in securing long-term persistence in the attacks that made use of this threat. 20141210
40 54884899-35b8-48a3-9da2-15c6950d210b 1635 Other text Regin 20141210
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68