Merge branch 'hotfix-2.3.59'

pull/468/head v2.3.59
Iglocska 2015-04-08 22:55:08 +02:00
commit 356e9ec383
28 changed files with 367 additions and 92 deletions

3
.gitignore vendored
View File

@ -37,6 +37,7 @@
/app/Config/database.php
/app/Config/core.php
/app/Config/config.php
/cakephp
/app/Lib/cakephp
/app/webroot/gpg.asc
/app/tmp/logs
*.swp

View File

@ -26,7 +26,7 @@ rpm -Uvh epel.rpm
yum install vim
# Install the dependencies:
yum install gcc git zip redis mysql-server php-mysql python-devel python-pip libxslt-devel zlib-devel php-devel
yum install gcc git zip redis mysql-server php-mysql python-devel python-pip libxslt-devel zlib-devel php-devel php-xml
yum install php-pear php-pecl-geoip
pear channel-update pear.php.net
@ -77,7 +77,7 @@ git submodule update
# Once done, install CakeResque along with its dependencies if you intend to use the built in background jobs:
cd /var/www/MISP/app
curl -s https://getcomposer.org/installer | php
php composer.phar require --no-update kamisama/cake-resque:4.1.0
php composer.phar require kamisama/cake-resque:4.1.2
php composer.phar config vendor-dir Vendor
php composer.phar install
@ -123,8 +123,9 @@ mysql> grant usage on *.* to misp@localhost identified by 'XXXXXXXXX';
mysql> grant all privileges on misp.* to misp@localhost ;
mysql> exit
# Import the empty MySQL database from MYSQL.sql
cd /var/www/MISP
# Import the empty MySQL database from MYSQL.sql
mysql -u misp -p misp < INSTALL/MYSQL.sql
@ -191,7 +192,8 @@ chmod 700 /var/www/MISP/.gnupg
gpg --homedir /var/www/MISP/.gnupg --gen-key
chown -R apache:apache /var/www/MISP/.gnupg
# Recommended key type: RSA
# The email address should match the one set int he config.php configuration file
# The email address should match the one set in the config.php configuration file
# Make sure that you use the same settings in the MISP Server Settings tool (Described on line 212)
# And export the public key to the webroot
sudo -u apache gpg --homedir /var/www/MISP/.gnupg --export --armor YOUR-EMAIL > /var/www/MISP/app/webroot/gpg.asc
@ -222,6 +224,11 @@ chown -R apache:apache /var/www/MISP/<directory path with an indicated issue>
# Make sure that the STIX libraries and GnuPG work as intended, if not, refer to INSTALL.txt's paragraphs dealing with these two items
# If anything goes wrong, make sure that you check MISP's logs for errors:
# /var/www/MISP/app/tmp/logs/error.log
# /var/www/MISP/app/tmp/logs/resque-worker-error.log
# /var/www/MISP/app/tmp/logs/resque-scheduler-error.log
# /var/www/MISP/app/tmp/logs/resque-2015-01-01.log //where the actual date is the current date
Recommended actions
-------------------

View File

@ -26,7 +26,7 @@ rpm -Uvh epel.rpm
yum install vim
# Install the dependencies:
yum install git httpd zip php redis mysql-server php-mysql python-devel python-pip libxslt-devel zlib-devel php-devel
yum install git httpd zip php redis mysql-server php-mysql python-devel python-pip libxslt-devel zlib-devel php-devel php-xml
yum install php-pear php-pecl-geoip
pear channel-update pear.php.net
@ -77,7 +77,7 @@ git submodule update
# Once done, install CakeResque along with its dependencies if you intend to use the built in background jobs:
cd /var/www/MISP/app
curl -s https://getcomposer.org/installer | php
php composer.phar require --no-update kamisama/cake-resque:4.1.0
php composer.phar require kamisama/cake-resque:4.1.2
php composer.phar config vendor-dir Vendor
php composer.phar install
@ -127,8 +127,9 @@ MariaDB [(none)]> grant usage on *.* to misp@localhost identified by 'XXXXXXXXX'
MariaDB [(none)]> grant all privileges on misp.* to misp@localhost ;
MariaDB [(none)]> exit
# Import the empty MySQL database from MYSQL.sql
cd /var/www/MISP
# Import the empty MySQL database from MYSQL.sql
mysql -u misp -p misp < INSTALL/MYSQL.sql
@ -205,7 +206,8 @@ chmod 700 /var/www/MISP/.gnupg
gpg --homedir /var/www/MISP/.gnupg --gen-key
chown -R apache:apache /var/www/MISP/.gnupg
# Recommended key type: RSA
# The email address should match the one set int he config.php configuration file
# The email address should match the one set in the config.php configuration file
# Make sure that you use the same settings in the MISP Server Settings tool (Described on line 226)
# And export the public key to the webroot
sudo -u apache gpg --homedir /var/www/MISP/.gnupg --export --armor YOUR-EMAIL > /var/www/MISP/app/webroot/gpg.asc
@ -236,6 +238,11 @@ chown -R apache:apache /var/www/MISP/<directory path with an indicated issue>
# Make sure that the STIX libraries and GnuPG work as intended, if not, refer to INSTALL.txt's paragraphs dealing with these two items
# If anything goes wrong, make sure that you check MISP's logs for errors:
# /var/www/MISP/app/tmp/logs/error.log
# /var/www/MISP/app/tmp/logs/resque-worker-error.log
# /var/www/MISP/app/tmp/logs/resque-scheduler-error.log
# /var/www/MISP/app/tmp/logs/resque-2015-01-01.log //where the actual date is the current date
Recommended actions
-------------------

View File

@ -14,6 +14,7 @@ Install a minimal ubuntu 14.04-server system with the software:
- Mail server
You will get some questions, you will probably want to set:
sudo apt-get install postfix
- Postfix Configuration: Satellite system
Make sure your system is up2date:
@ -64,7 +65,7 @@ git submodule update
# Once done, install CakeResque along with its dependencies if you intend to use the built in background jobs:
cd /var/www/MISP/app
curl -s https://getcomposer.org/installer | php
php composer.phar require --no-update kamisama/cake-resque:4.1.0
php composer.phar require kamisama/cake-resque:4.1.2
php composer.phar config vendor-dir Vendor
php composer.phar install
@ -102,7 +103,8 @@ mysql> exit
cd /var/www/MISP
# Import the empty MySQL database from MYSQL.sql
mysql -u misp -p<password> misp < INSTALL/MYSQL.sql
mysql -u misp -p misp < INSTALL/MYSQL.sql
#enter the password you set previously
7/ Apache configuration
@ -163,8 +165,8 @@ chown www-data:www-data /var/www/MISP/.gnupg
chmod 700 /var/www/MISP/.gnupg
sudo -u www-data gpg --homedir /var/www/MISP/.gnupg --gen-key
# Recommended key type: RSA
# The email address should match the one set int he bootstrap.php configuration file
# Make sure that you use the same settings in the MISP Server Settings tool tool (Described on line 184)
# The email address should match the one set in the config.php configuration file
# Make sure that you use the same settings in the MISP Server Settings tool (Described on line 184)
# And export the public key to the webroot
sudo -u www-data gpg --homedir /var/www/MISP/.gnupg --export --armor YOUR-EMAIL > /var/www/MISP/app/webroot/gpg.asc

54
INSTALL/UPDATE.txt Normal file
View File

@ -0,0 +1,54 @@
# After installing MISP you can keep it up to date by periodically running the commands below.
# 1. Update the MISP code to the latest hotfix. If a new major version (2.4.x) has been released, refer to UPGRADE.txt instead.
cd /var/www/MISP
git pull
# 2. Update CakePHP to the latest 2.6 code
cd /var/www/MISP/Lib/cakephp
git fetch origin
git checkout 2.6
# 3. Update Mitre's STIX and its dependencies
cd /var/www/MISP/app/files/scripts/python-cybox
git pull
python setup.py install
cd /var/www/MISP/app/files/scripts/python-stix
git pull
python setup.py install
# 4. Update CakeResque and it's dependencies
cd /var/www/MISP/app
# Edit composer.json so that cake-resque is allowed to be updated
# "kamisama/cake-resque": ">=4.1.2"
vim composer.json
php composer.phar self-update
php composer.phar update
# To use the scheduler worker for scheduled tasks, do the following:
cp -fa /var/www/MISP/INSTALL/setup/config.php /var/www/MISP/app/Plugin/CakeResque/Config/config.php
# 5. Make sure all file permissions are set correctly
chown -R root:www-data /var/www/MISP
find /var/www/MISP -type d -exec chmod g=rx {} \;
chmod -R g+r,o= /var/www/MISP
chown www-data:www-data /var/www/MISP/app/files
chown www-data:www-data /var/www/MISP/app/files/terms
chown www-data:www-data /var/www/MISP/app/files/scripts/tmp
chown www-data:www-data /var/www/MISP/app/Plugin/CakeResque/tmp
chown -R www-data:www-data /var/www/MISP/app/tmp
chown -R www-data:www-data /var/www/MISP/app/webroot/img/orgs
chown -R www-data:www-data /var/www/MISP/app/webroot/img/custom
# 6. Restart the CakeResque workers
su www-data -c 'bash /var/www/MISP/app/Console/worker/start.sh'
# You can also do this using the MISP application by navigating to the workers tab in the server settings and clicking on the "Restart all workers" button.

View File

@ -32,7 +32,7 @@ python setup.py install
# install / update CakeResque (using the background workers is optional buy highly recommended)
cd /var/www/MISP/app
curl -s https://getcomposer.org/installer | php
php composer.phar require --no-update kamisama/cake-resque:4.1.0
php composer.phar require kamisama/cake-resque:4.1.2
php composer.phar config vendor-dir Vendor
php composer.phar install
@ -78,4 +78,4 @@ chown -R www-data:www-data /var/www/MISP/<directory path with an indicated issue
# Amend your rc.local using the following command to always start the background workers using the apache user (substitute www-data with your apache user)
su www-data -c 'bash /var/www/MISP/app/Console/worker/start.sh'
# Start the background workers using the application by navigating to the workers tab in the server settings and clicking on the "Restart all workers" button.
# Start the background workers using the application by navigating to the workers tab in the server settings and clicking on the "Restart all workers" button.

View File

@ -0,0 +1,23 @@
#!/usr/bin/python
'''
Example file on how to get the exported IDS data from MISP
Add your API key, set the MISP host and define the output file.
'''
import urllib2
MISP_HOST="http:/"
API_KEY=""
EXPORT_DATA="events/nids/suricata/download"
OUTPUT_FILE="misp-suricata"
URL="%s/%s" % (MISP_HOST, EXPORT_DATA)
request = urllib2.Request(URL)
f = open(OUTPUT_FILE,'w')
request.add_header('Authorization', API_KEY)
data = urllib2.urlopen(request).read()
f.write(data)
f.close()

View File

@ -25,7 +25,8 @@ $config = array (
'tagging' => true,
'full_tags_on_event_index' => true,
'footer_logo' => '',
'take_ownership_xml_import' => false,
'take_ownership_xml_import' => false,
'unpublishedprivate' => false,
),
'GnuPG' =>
array (
@ -34,6 +35,14 @@ $config = array (
'homedir' => '',
'password' => '',
),
'Proxy' =>
array (
'host' => '',
'port' => '',
'method' => '',
'user' => '',
'password' => '',
),
'SecureAuth' =>
array (
'amount' => 5,

View File

@ -45,7 +45,7 @@ class EventShell extends AppShell
$eventIds = $this->Event->fetchEventIds($org, $isSiteAdmin);
$result = array();
$eventCount = count($eventIds);
$dir = new Folder(APP . DS . '/tmp/cached_exports/xml');
$dir = new Folder(APP . 'tmp/cached_exports/xml');
if ($isSiteAdmin) {
$file = new File($dir->pwd() . DS . 'misp.xml' . '.ADMIN.xml');
} else {
@ -192,7 +192,7 @@ class EventShell extends AppShell
$eventIds = $this->Event->fetchEventIds($org, $isSiteAdmin);
$eventCount = count($eventIds);
$attributes = array();
$dir = new Folder(APP . DS . '/tmp/cached_exports/' . $extra);
$dir = new Folder(APP . 'tmp/cached_exports/' . $extra);
if ($isSiteAdmin) {
$file = new File($dir->pwd() . DS . 'misp.' . $extra . '.ADMIN.csv');
} else {
@ -200,11 +200,13 @@ class EventShell extends AppShell
}
$file->write('uuid,event_id,category,type,value,to_ids,date' . PHP_EOL);
foreach ($eventIds as $k => $eventId) {
$chunk = "";
$attributes = $this->Event->csv($org, $isSiteAdmin, $eventId['Event']['id'], $ignore);
$attributes = $this->Whitelist->removeWhitelistedFromArray($attributes, true);
foreach ($attributes as $attribute) {
$file->append($attribute['Attribute']['uuid'] . ',' . $attribute['Attribute']['event_id'] . ',' . $attribute['Attribute']['category'] . ',' . $attribute['Attribute']['type'] . ',' . $attribute['Attribute']['value'] . ',' . intval($attribute['Attribute']['to_ids']) . ',' . $attribute['Attribute']['timestamp'] . PHP_EOL);
$chunk .= $attribute['Attribute']['uuid'] . ',' . $attribute['Attribute']['event_id'] . ',' . $attribute['Attribute']['category'] . ',' . $attribute['Attribute']['type'] . ',' . $attribute['Attribute']['value'] . ',' . intval($attribute['Attribute']['to_ids']) . ',' . $attribute['Attribute']['timestamp'] . PHP_EOL;
}
$file->append($chunk);
if ($k % 10 == 0) {
$this->Job->saveField('progress', $k / $eventCount * 80);
}
@ -333,7 +335,7 @@ class EventShell extends AppShell
// Now that we have figured out when the next execution should happen, it's time to enqueue it.
$process_id = CakeResque::enqueueAt(
$task['Task']['next_execution_time'],
'default',
'cache',
'EventShell',
array('enqueueCaching', $task['Task']['next_execution_time']),
true

View File

@ -58,6 +58,7 @@ class AttributesController extends AppController {
'AND' => array(
'Attribute.distribution >' => 0,
'Event.distribution >' => 0,
Configure::read('MISP.unpublishedprivate') ? array('Event.published =' => 1) : array(),
)))));
}
@ -1281,9 +1282,17 @@ class AttributesController extends AppController {
// merge in private conditions
$this->paginate = Set::merge($this->paginate, array(
'conditions' =>
array("OR" => array(
array('Event.org =' => $this->Auth->user('org')),
array("AND" => array('Event.org !=' => $this->Auth->user('org')), array('Event.distribution !=' => 0), array('Attribute.distribution !=' => 0)))),
array("OR" =>
array(
array('Event.org =' => $this->Auth->user('org')),
array("AND" =>
array('Event.org !=' => $this->Auth->user('org')),
array('Event.distribution !=' => 0),
array('Attribute.distribution !=' => 0),
Configure::read('MISP.unpublishedprivate') ? array('Event.published =' => 1) : array(),
)
)
)
)
);
}
@ -1369,8 +1378,14 @@ class AttributesController extends AppController {
public function searchAlternate($data) {
$data['AND'][] = array(
"OR" => array(
array('Event.org =' => $this->Auth->user('org')),
array("AND" => array('Event.org !=' => $this->Auth->user('org')), array('Event.distribution !=' => 0), array('Attribute.distribution !=' => 0))));
array('Event.org =' => $this->Auth->user('org')),
array("AND" => array('Event.org !=' => $this->Auth->user('org')),
array('Event.distribution !=' => 0),
array('Attribute.distribution !=' => 0),
Configure::read('MISP.unpublishedprivate') ? array('Event.published =' => 1) : array(),
)
)
);
$attributes = $this->Attribute->find('all', array(
'conditions' => $data,
'fields' => array(
@ -1555,7 +1570,11 @@ class AttributesController extends AppController {
if (!$user['User']['siteAdmin']) {
$temp = array();
$temp['AND'] = array('Event.distribution >' => 0, 'Attribute.distribution >' => 0);
$temp['AND'] = array(
'Event.distribution >' => 0,
'Attribute.distribution >' => 0,
Configure::read('MISP.unpublishedprivate') ? array('Event.published =' => 1) : array()
);
$subcondition['OR'][] = $temp;
$subcondition['OR'][] = array('Event.org' => $user['User']['org']);
array_push($conditions['AND'], $subcondition);

View File

@ -70,9 +70,15 @@ class EventsController extends AppController {
$this->paginate = Set::merge($this->paginate,array(
'conditions' =>
array("OR" => array(
array('Event.org =' => $this->Auth->user('org')),
array('Event.distribution >' => 0),
))));
array('Event.org =' => $this->Auth->user('org')),
"AND" => array(
array('Event.distribution >' => 0),
Configure::read('MISP.unpublishedprivate') ? array('Event.published =' => 1) : array(),
)
)
)
)
);
}
}
@ -2444,7 +2450,11 @@ class EventsController extends AppController {
if (!$user['User']['siteAdmin']) {
$temp = array();
$temp['AND'] = array('Event.distribution >' => 0, 'Attribute.distribution >' => 0);
$temp['AND'] = array(
'Event.distribution >' => 0,
'Attribute.distribution >' => 0,
Configure::read('MISP.unpublishedprivate') ? array('Event.published =' => 1) : array()
);
$subcondition['OR'][] = $temp;
$subcondition['OR'][] = array('Event.org' => $user['User']['org']);
array_push($conditions['AND'], $subcondition);
@ -3165,4 +3175,4 @@ class EventsController extends AppController {
$this->set('id', $id);
$this->render('ajax/exportChoice');
}
}
}

View File

@ -289,11 +289,13 @@ class ServersController extends AppController {
$tabs = array(
'MISP' => array('count' => 0, 'errors' => 0, 'severity' => 5),
'GnuPG' => array('count' => 0, 'errors' => 0, 'severity' => 5),
'Proxy' => array('count' => 0, 'errors' => 0, 'severity' => 5),
'Security' => array('count' => 0, 'errors' => 0, 'severity' => 5),
'misc' => array('count' => 0, 'errors' => 0, 'severity' => 5)
);
$writeableErrors = array(0 => 'OK', 1 => 'Directory doesn\'t exist', 2 => 'Directory is not writeable');
$gpgErrors = array(0 => 'OK', 1 => 'FAIL: settings not set', 2 => 'FAIL: bad GnuPG.*', 3 => 'FAIL: encrypt failed');
$proxyErrors = array(0 => 'OK', 1 => 'not configured (so not tested)', 2 => 'Getting URL via proxy failed');
$stixErrors = array(0 => 'ERROR', 1 => 'OK');
$results = $this->Server->serverSettingsRead();
@ -394,7 +396,29 @@ class ServersController extends AppController {
$gpgStatus = 1;
}
if ($gpgStatus != 0) $diagnostic_errors++;
// if Proxy is set up in the settings, try to connect to a test URL
$proxyStatus = 0;
$proxy = Configure::read('Proxy');
if(!empty($proxy['host'])) {
App::uses('SyncTool', 'Tools');
$syncTool = new SyncTool();
try {
$HttpSocket = $syncTool->setupHttpSocket();
$proxyResponse = $HttpSocket->get('http://www.example.com/');
} catch (Exception $e) {
$proxyStatus = 2;
}
if(empty($proxyResponse) || $proxyResponse->code > 399) {
$proxyStatus = 2;
}
} else {
$proxyStatus = 1;
}
if ($proxyStatus > 1) $diagnostic_errors++;
$this->set('gpgStatus', $gpgStatus);
$this->set('proxyStatus', $proxyStatus);
$this->set('diagnostic_errors', $diagnostic_errors);
$this->set('tab', $tab);
$this->set('tabs', $tabs);
@ -403,6 +427,7 @@ class ServersController extends AppController {
$this->set('writeableErrors', $writeableErrors);
$this->set('gpgErrors', $gpgErrors);
$this->set('proxyErrors', $proxyErrors);
$this->set('stixErrors', $stixErrors);
if (Configure::read('MISP.background_jobs')) {
@ -437,7 +462,7 @@ class ServersController extends AppController {
foreach ($dumpResults as &$dr) {
unset($dr['description']);
}
$dump = array('gpgStatus' => $gpgErrors[$gpgStatus], 'stix' => $stixErrors[$stix], 'writeableDirs' => $writeableDirs, 'finalSettings' => $dumpResults);
$dump = array('gpgStatus' => $gpgErrors[$gpgStatus], 'proxyStatus' => $proxyErrors[$proxyStatus], 'stix' => $stixErrors[$stix], 'writeableDirs' => $writeableDirs, 'finalSettings' => $dumpResults);
$this->response->body(json_encode($dump, JSON_PRETTY_PRINT));
$this->response->type('json');
$this->response->download('MISP.report.json');
@ -453,12 +478,16 @@ class ServersController extends AppController {
private function __checkVersion() {
if (!$this->_isSiteAdmin()) throw new MethodNotAllowedException();
set_error_handler(function() {});
$options = array('http' => array('user_agent'=> $_SERVER['HTTP_USER_AGENT']));
$context = stream_context_create($options);
$tags = file_get_contents('https://api.github.com/repos/MISP/MISP/tags', false, $context);
restore_error_handler();
if ($tags != false) {
App::uses('SyncTool', 'Tools');
$syncTool = new SyncTool();
try {
$HttpSocket = $syncTool->setupHttpSocket();
$response = $HttpSocket->get('https://api.github.com/repos/MISP/MISP/tags');
$tags = $response->body;
} catch (Exception $e) {
return false;
}
if ($response->isOK() && !empty($tags)) {
$json_decoded_tags = json_decode($tags);
// find the latest version tag in the v[major].[minor].[hotfix] format

View File

@ -50,6 +50,7 @@ class ShadowAttributesController extends AppController {
'AND' => array(
'ShadowAttribute.org =' => $this->Auth->user('org'),
'Event.distribution >' => 0,
Configure::read('MISP.unpublishedprivate') ? array('Event.published =' => 1) : array(),
),
)
)));

View File

@ -37,7 +37,15 @@ class TagsController extends AppController {
$eventIDs[] = $eventTag['event_id'];
}
$conditions = array('Event.id' => $eventIDs);
if (!$this->_isSiteAdmin()) $conditions = array_merge($conditions, array('OR' => array(array('Event.distribution >' => 0), array('Event.orgc' => $this->Auth->user('org')))));
if (!$this->_isSiteAdmin()) $conditions = array_merge(
$conditions,
array('OR' => array(
array('AND' => array(
array('Event.distribution >' => 0),
array('Event.published =' => 1)
)),
array('Event.orgc' => $this->Auth->user('org'))
)));
$events = $this->Event->find('all', array(
'fields' => array('Event.id', 'Event.distribution', 'Event.orgc'),
'conditions' => $conditions
@ -136,4 +144,4 @@ class TagsController extends AppController {
$this->set('id', $id);
$this->render('ajax/view_tag');
}
}
}

View File

@ -2,12 +2,18 @@
class SyncTool {
// take a server as parameter and return a HttpSocket object using the ssl options defined in the server settings
public function setupHttpSocket($server) {
public function setupHttpSocket($server = null) {
$params = array();
App::uses('HttpSocket', 'Network/Http');
if ($server['Server']['cert_file']) $params['ssl_cafile'] = APP . "files" . DS . "certs" . DS . $server['Server']['id'] . '.pem';
if ($server['Server']['self_signed']) $params['ssl_allow_self_signed'] = $server['Server']['self_signed'];
if(!empty($server)) {
if ($server['Server']['cert_file']) $params['ssl_cafile'] = APP . "files" . DS . "certs" . DS . $server['Server']['id'] . '.pem';
if ($server['Server']['self_signed']) $params['ssl_allow_self_signed'] = $server['Server']['self_signed'];
}
$HttpSocket = new HttpSocket($params);
$proxy = Configure::read('Proxy');
$HttpSocket->configProxy($proxy['host'], $proxy['port'], $proxy['method'], $proxy['user'], $proxy['password']);
return $HttpSocket;
}
}

@ -1 +1 @@
Subproject commit a0aac5cfa9acf2ccbde65c45ad6ee06ecd32fb54
Subproject commit 4c61b579c40863ada019e1e08c6195ae612c589f

View File

@ -809,7 +809,10 @@ class Event extends AppModel {
$conditions = array();
if (!$isSiteAdmin) {
$conditions['OR'] = array(
'Event.distribution >' => 0,
"AND" => array(
'Event.distribution >' => 0,
Configure::read('MISP.unpublishedprivate') ? array('Event.published =' => 1) : array()
),
'Event.org LIKE' => $org
);
}
@ -845,7 +848,10 @@ class Event extends AppModel {
//restricting to non-private or same org if the user is not a site-admin.
if (!$isSiteAdmin) {
$conditions['AND']['OR'] = array(
'Event.distribution >' => 0,
"AND" => array(
'Event.distribution >' => 0,
Configure::read('MISP.unpublishedprivate') ? array('Event.published =' => 1) : array(),
),
'Event.org LIKE' => $org
);
$conditionsAttributes['OR'] = array(
@ -942,7 +948,13 @@ class Event extends AppModel {
if ($from) $econditions['AND'][] = array('Event.date >=' => $from);
if ($to) $econditions['AND'][] = array('Event.date <=' => $to);
// 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(!$isSiteAdmin) $econditions['AND']['OR'] = array('Event.distribution >' => 0, 'Event.org =' => $org);
if(!$isSiteAdmin) $econditions['AND']['OR'] = array(
"AND" => array(
'Event.distribution >' => 0,
Configure::read('MISP.unpublishedprivate') ? array('Event.published =' => 1) : array(),
),
'Event.org =' => $org
);
if ($eventid == 0 && $ignore == 0) $econditions['AND'][] = array('Event.published =' => 1);
// If it's a full download (eventid == false) and the user is not a site admin, we need to first find all the events that the user can see and save the IDs
@ -1060,7 +1072,7 @@ class Event extends AppModel {
$job = ClassRegistry::init('Job');
$job->create();
$data = array(
'worker' => 'default',
'worker' => 'email',
'job_type' => 'publish_alert_email',
'job_input' => 'Event: ' . $id,
'status' => 0,
@ -1071,7 +1083,7 @@ class Event extends AppModel {
$job->save($data);
$jobId = $job->id;
$process_id = CakeResque::enqueue(
'default',
'email',
'EventShell',
array('alertemail', $user['org'], $jobId, $id)
);
@ -1149,7 +1161,7 @@ class Event extends AppModel {
if (Configure::read('MISP.extended_alert_subject')) {
$subject = preg_replace( "/\r|\n/", "", $event['Event']['info']);
if (strlen($subject) > 55) {
if (strlen($subject) > 58) {
$subject = substr($subject, 0, 55) . '... - ';
} else {
$subject .= " - ";
@ -1643,7 +1655,7 @@ class Event extends AppModel {
$job = ClassRegistry::init('Job');
$job->create();
$data = array(
'worker' => 'default',
'worker' => 'email',
'job_type' => 'contact_alert',
'job_input' => 'To entire org: ' . $all,
'status' => 0,
@ -1654,7 +1666,7 @@ class Event extends AppModel {
$job->save($data);
$jobId = $job->id;
$process_id = CakeResque::enqueue(
'default',
'email',
'EventShell',
array('contactemail', $id, $message, $all, $user['id'], $isSiteAdmin, $jobId)
);
@ -1851,7 +1863,7 @@ class Event extends AppModel {
$scriptFile = APP . "files" . DS . "scripts" . DS . "misp2stix.py";
// Execute the python script and point it to the temporary filename
$result = shell_exec('python ' . $scriptFile . ' ' . $randomFileName . ' ' . $returnType);
$result = shell_exec('python ' . $scriptFile . ' ' . $randomFileName . ' ' . $returnType . ' ' . Configure::read('MISP.baseurl') . ' "' . Configure::read('MISP.org') . '"');
// The result of the script will be a returned JSON object with 2 variables: success (boolean) and message
// If success = 1 then the temporary output file was successfully written, otherwise an error message is passed along

View File

@ -381,6 +381,14 @@ class Server extends AppModel {
'test' => 'testBool',
'type' => 'boolean'
),
'unpublishedprivate' => array(
'level' => 2,
'description' => 'True will deny access to unpublished events to users outside the organization of the submitter except site admins.',
'value' => '',
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
),
'GnuPG' => array(
'branch' => 1,
@ -417,6 +425,49 @@ class Server extends AppModel {
'type' => 'string',
),
),
'Proxy' => array(
'branch' => 1,
'host' => array(
'level' => 2,
'description' => 'The hostname of an HTTP proxy for outgoing sync requests. Leave empty to not use a proxy.',
'value' => '',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string',
),
'port' => array(
'level' => 2,
'description' => 'The TCP port for the HTTP proxy.',
'value' => '',
'errorMessage' => '',
'test' => 'testForNumeric',
'type' => 'numeric',
),
'method' => array(
'level' => 2,
'description' => 'The authentication method for the HTTP proxy. Currently supported are Basic or Digest. Leave empty for no proxy authentication.',
'value' => '',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string',
),
'user' => array(
'level' => 2,
'description' => 'The authentication username for the HTTP proxy.',
'value' => '',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string',
),
'password' => array(
'level' => 2,
'description' => 'The authentication password for the HTTP proxy.',
'value' => '',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string',
),
),
'Security' => array(
'branch' => 1,
'salt' => array(
@ -1008,7 +1059,7 @@ class Server extends AppModel {
public function serverSettingsSaveValue($setting, $value) {
Configure::write($setting, $value);
Configure::dump('config.php', 'default', array('MISP', 'GnuPG', 'SecureAuth', 'Security', 'debug'));
Configure::dump('config.php', 'default', array('MISP', 'GnuPG', 'Proxy', 'SecureAuth', 'Security', 'debug'));
}
public function checkVersion($newest) {

@ -1 +0,0 @@
Subproject commit 34f9a7cd370bfb2706b9bd6b54fb8ede17e5e5bd

View File

@ -27,7 +27,7 @@
</td>
<td>
<?php
if (strlen(h($event['Event']['info'])) > 60) {
if (strlen(h($event['Event']['info'])) > 63) {
echo (substr(h($event['Event']['info']), 0, 60)) . '...';
} else echo h($event['Event']['info']);
?>
@ -52,4 +52,4 @@
</div>
<?php
echo $this->element('side_menu', array('menuList' => 'event-collection', 'menuItem' => 'searchAttributes'));
?>
?>

View File

@ -86,4 +86,18 @@
echo 'GnuPG installation and settings....<span style="color:' . $colour . ';">' . $message . '</span>';
?>
</div>
</div>
<h3>
Proxy
</h3>
<p>This tool tests whether your HTTP proxy settings are correct.</p>
<div style="background-color:#f7f7f9;width:300px;">
<?php
$colour = 'green';
$message = $proxyErrors[$proxyStatus];
if ($proxyStatus > 1) {
$colour = 'red';
}
echo 'Proxy settings....<span style="color:' . $colour . ';">' . $message . '</span>';
?>
</div>
</div>

View File

@ -12,7 +12,7 @@ $mayPublish = ($isAclPublish && $event['Event']['orgc'] == $me['org']);
$left = true;
}
$title = $event['Event']['info'];
if (strlen($title) > 55) $title = substr($title, 0, 55) . '...';
if (strlen($title) > 58) $title = substr($title, 0, 55) . '...';
?>
<div class="row-fluid">
<div class="span8">
@ -252,4 +252,4 @@ $(document).ready(function () {
$('#addTagButton').hide();
});
});
</script>
</script>

View File

@ -9,7 +9,7 @@ App::uses('AppHelper', 'View/Helper');
$active = '';
$pivot['info'] = h($pivot['info']);
// Truncate string if longer than (11 - length of event id) chars to fit the pivot bubble
if (strlen($pivot['info']) > (11 - strlen((string)$pivot['id']))) {
if (strlen($pivot['info']) > (11 - strlen((string)$pivot['id'])) && strlen($pivot['info']) > 9) {
$text .= substr($pivot['info'], 0, 6) . '...';
} else {
$text .= $pivot['info'];

View File

@ -31,6 +31,7 @@
<li><b>Overview</b>: General overview of the current state of your MISP installation</li>
<li><b>MISP settings</b>: Basic MISP settings. This includes the way MISP handles the default settings for distribution settings, whether background jobs are enabled, etc</li>
<li><b>GnuPG settings</b>: GPG related settings.</li>
<li><b>Proxy settings</b>: HTTP proxy related settings.</li>
<li><b>Security settings</b>: Settings controlling the brute-force protection and the application's salt key.</li>
<li><b>Misc settings</b>: You change the debug options here, but make sure that debug is always disabled on a production system.</li>
<li><b>Diagnostics</b>: The diagnostics tool checks if all directories that MISP uses to store data are writeable by the apache user. Also, the tool checks whether the STIX libraries and GPG are working as intended.</li>
@ -240,4 +241,4 @@
<li><b>Message</b>: This field shows when the job was queued by the scheduler for execution. </li>
</ul>
<br /><img src="/img/doc/schedule.png" alt = "" title = "Site administrators can schedule reccuring tasks on this page."/><br />
</div>
</div>

View File

@ -2,7 +2,7 @@
<h2>Server settings</h2>
<?php
echo $this->element('healthElements/tabs');
if (in_array($tab, array('MISP', 'Security', 'GnuPG', 'misc'))) {
if (in_array($tab, array('MISP', 'Security', 'GnuPG', 'Proxy', 'misc'))) {
echo $this->element('healthElements/settings_tab');
} else if ($tab == 'diagnostics') {
echo $this->element('healthElements/diagnostics');
@ -17,4 +17,4 @@
</div>
<?php
echo $this->element('side_menu', array('menuList' => 'admin', 'menuItem' => 'serverSettings'));
?>
?>

View File

@ -1,7 +1,7 @@
from stix.extensions.identity.ciq_identity_3_0 import (CIQIdentity3_0Instance, STIXCIQIdentity3_0, OrganisationInfo, PartyName, Address, ElectronicAddressIdentifier, FreeTextAddress)
from stix.common import Identity
def resolveIdentityAttribute(incident, attribute):
def resolveIdentityAttribute(incident, attribute, namespace):
ciq_identity = CIQIdentity3_0Instance()
identity_spec = STIXCIQIdentity3_0()
if attribute["type"] == 'target-user':
@ -20,6 +20,6 @@ def resolveIdentityAttribute(incident, attribute):
ciq_identity.id_ = "example:Identity-" + attribute["uuid"]
# is this a good idea?
ciq_identity.name = "MISP Attribute #" + attribute["id"] + " uuid: " + attribute["uuid"]
ciq_identity.name = attribute["type"] + ": " + attribute["value"] + " (MISP Attribute #" + attribute["id"] + ")"
incident.add_victim(ciq_identity)
return incident

View File

@ -1,4 +1,4 @@
from cybox.core import Observable, ObservableComposition
from cybox.core import Object, Observable, ObservableComposition
from cybox.objects.file_object import File
from cybox.objects.address_object import Address
from cybox.objects.hostname_object import Hostname
@ -40,7 +40,11 @@ def generateObservable(indicator, attribute):
if (attribute["type"] in simple_type_to_method.keys()):
action = getattr(this_module, simple_type_to_method[attribute["type"]], None)
if (action != None):
observable = action(attribute)
property = action(attribute)
object = Object(property)
object.id_ = cybox.utils.idgen.__generator.namespace.prefix + ":" + property.__class__.__name__ + "-" + attribute["uuid"]
observable = Observable(object)
observable.id_ = cybox.utils.idgen.__generator.namespace.prefix + ":observable-" + attribute["uuid"]
indicator.add_observable(observable)
def resolveFileObservable(attribute):
@ -177,30 +181,44 @@ def resolvePatternObservable(attribute):
# create an artifact object for the malware-sample type.
def createArtifactObject(indicator, attribute):
artifact = Artifact(data = attribute["data"])
indicator.add_observable(artifact)
artifact.parent.id_ = cybox.utils.idgen.__generator.namespace.prefix + ":artifact-" + attribute["uuid"]
observable = Observable(artifact)
observable.id_ = cybox.utils.idgen.__generator.namespace.prefix + ":observable-artifact-" + attribute["uuid"]
indicator.add_observable(observable)
# return either a composition if data is set in attribute, or just an observable with a filename if it's not set
def returnAttachmentComposition(attribute):
file_object = File()
file_object.file_name = attribute["value"]
file_object.parent.id_ = cybox.utils.idgen.__generator.namespace.prefix + ":file-" + attribute["uuid"]
observable = Observable()
if "data" in attribute:
artifact = Artifact(data = attribute["data"])
composition = ObservableComposition(observables = [artifact, file_object])
artifact.parent.id_ = cybox.utils.idgen.__generator.namespace.prefix + ":artifact-" + attribute["uuid"]
observable_artifact = Observable(artifact)
observable_artifact.id_ = cybox.utils.idgen.__generator.namespace.prefix + ":observable-artifact-" + attribute["uuid"]
observable_file = Observable(file_object)
observable_file.id_ = cybox.utils.idgen.__generator.namespace.prefix + ":observable-file-" + attribute["uuid"]
composition = ObservableComposition(observables = [observable_artifact, observable_file])
observable.observable_composition = composition
else:
observable = Observable(file_object)
observable.id_ = cybox.utils.idgen.__generator.namespace.prefix + ":observable-" + attribute["uuid"]
if attribute["comment"] != "":
observable.description = attribute["comment"]
return observable
# email-attachment are mapped to an email message observable that contains the attachment as a file object
def generateEmailAttachmentObject(indicator, filename):
def generateEmailAttachmentObject(indicator, attribute):
file_object = File()
file_object.file_name = filename
file_object.file_name = attribute["value"]
email = EmailMessage()
email.attachments = Attachments()
email.add_related(file_object, "Contains", inline=True)
file_object.parent.id_ = cybox.utils.idgen.__generator.namespace.prefix + ":file-" + attribute["uuid"]
email.attachments.append(file_object.parent.id_)
indicator.observable = email
email.parent.id_ = cybox.utils.idgen.__generator.namespace.prefix + ":EmailMessage-" + attribute["uuid"]
observable = Observable(email)
observable.id_ = cybox.utils.idgen.__generator.namespace.prefix + ":observable-" + attribute["uuid"]
indicator.observable = observable

View File

@ -20,10 +20,6 @@ from cybox.utils import Namespace
namespace = ['https://github.com/MISP/MISP', 'MISP']
cybox.utils.idgen.set_id_namespace(Namespace(namespace[0], namespace[1]))
stix.utils.idgen.set_id_namespace({namespace[0]: namespace[1]})
NS_DICT = {
"http://cybox.mitre.org/common-2" : 'cyboxCommon',
"http://cybox.mitre.org/cybox-2" : 'cybox',
@ -55,7 +51,6 @@ NS_DICT = {
"urn:oasis:names:tc:ciq:xal:3" : 'xal',
"urn:oasis:names:tc:ciq:xnl:3" : 'xnl',
"urn:oasis:names:tc:ciq:xpil:3" : 'xpil',
namespace[0] : namespace[1]
}
SCHEMALOC_DICT = {
@ -126,7 +121,7 @@ def saveFile(args, pathname, package):
def generateMainPackage(events):
stix_package = STIXPackage()
stix_header = STIXHeader()
stix_header.title="Export from MISP"
stix_header.title="Export from " + namespace[1] + " MISP"
stix_header.package_intents="Threat Report"
stix_package.stix_header = stix_header
return stix_package
@ -134,9 +129,10 @@ def generateMainPackage(events):
# generate a package for each event
def generateEventPackage(event):
package_name = namespace[1] + ':STIXPackage-' + event["Event"]["uuid"]
stix_package = STIXPackage(id_=package_name)
timestamp = getDateFromTimestamp(int(event["Event"]["timestamp"]))
stix_package = STIXPackage(id_=package_name, timestamp=timestamp)
stix_header = STIXHeader()
stix_header.title="MISP event #" + event["Event"]["id"] + " uuid: " + event["Event"]["uuid"]
stix_header.title=event["Event"]["info"] + " (MISP Event #" + event["Event"]["id"] + ")"
stix_header.package_intents="Threat Report"
stix_package.stix_header = stix_header
objects = generateSTIXObjects(event)
@ -189,9 +185,8 @@ def resolveAttributes(incident, ttps, attributes):
# Create the indicator and pass the attribute further for observable creation - this can be called from resolveattributes directly or from handleNonindicatorAttribute, for some special cases
def handleIndicatorAttribute(incident, ttps, attribute):
indicator = generateIndicator(attribute)
indicator.title = "MISP Attribute #" + attribute["id"] + " uuid: " + attribute["uuid"]
if attribute["type"] == "email-attachment":
generateEmailAttachmentObject(indicator, attribute["value"])
generateEmailAttachmentObject(indicator, attribute)
else:
generateObservable(indicator, attribute)
if "data" in attribute:
@ -227,7 +222,7 @@ def handleNonIndicatorAttribute(incident, ttps, attribute):
else:
addReference(incident, attribute["value"])
elif attribute["type"].startswith('target-'):
resolveIdentityAttribute(incident, attribute)
resolveIdentityAttribute(incident, attribute, namespace[1])
elif attribute["type"] == "attachment":
observable = returnAttachmentComposition(attribute)
related_observable = RelatedObservable(observable, relationship=attribute["category"])
@ -236,14 +231,14 @@ def handleNonIndicatorAttribute(incident, ttps, attribute):
# TTPs are only used to describe malware names currently (attribute with category Payload Type and type text/comment/other)
def generateTTP(incident, attribute):
ttp = TTP()
ttp = TTP(timestamp=getDateFromTimestamp(int(attribute["timestamp"])))
ttp.id_= namespace[1] + ":ttp-" + attribute["uuid"]
setTLP(ttp, attribute["distribution"])
ttp.title = "MISP Attribute #" + attribute["id"] + " uuid: " + attribute["uuid"]
ttp.title = attribute["category"] + ": " + attribute["value"] + " (MISP Attribute #" + attribute["id"] + ")"
if attribute["type"] == "vulnerability":
vulnerability = Vulnerability()
vulnerability.cve_id = attribute["value"]
et = ExploitTarget()
et = ExploitTarget(timestamp=getDateFromTimestamp(int(attribute["timestamp"])))
et.add_vulnerability(vulnerability)
ttp.exploit_targets.append(et)
else:
@ -258,9 +253,9 @@ def generateTTP(incident, attribute):
# Threat actors are currently only used for the category:attribution / type:(text|comment|other) attributes
def generateThreatActor(attribute):
ta = ThreatActor()
ta = ThreatActor(timestamp=getDateFromTimestamp(int(attribute["timestamp"])))
ta.id_= namespace[1] + ":threatactor-" + attribute["uuid"]
ta.title = "MISP Attribute #" + attribute["id"] + " uuid: " + attribute["uuid"]
ta.title = attribute["category"] + ": " + attribute["value"] + " (MISP Attribute #" + attribute["id"] + ")"
if attribute["comment"] != "":
ta.description = attribute["value"] + " (" + attribute["comment"] + ")"
else:
@ -269,17 +264,17 @@ def generateThreatActor(attribute):
# generate the indicator and add the relevant information
def generateIndicator(attribute):
indicator = Indicator()
indicator = Indicator(timestamp=getDateFromTimestamp(int(attribute["timestamp"])))
indicator.id_= namespace[1] + ":indicator-" + attribute["uuid"]
if attribute["comment"] != "":
indicator.description = attribute["comment"]
setTLP(indicator, attribute["distribution"])
indicator.title = "MISP Attribute #" + attribute["id"] + " uuid: " + attribute["uuid"]
indicator.title = attribute["category"] + ": " + attribute["value"] + " (MISP Attribute #" + attribute["id"] + ")"
confidence_description = "Derived from MISP's IDS flag. If an attribute is marked for IDS exports, the confidence will be high, otherwise none"
confidence_value = confidence_mapping.get(attribute["to_ids"], None)
if confidence_value is None:
return indicator
indicator.confidence = Confidence(value=confidence_value, description=confidence_description)
indicator.confidence = Confidence(value=confidence_value, description=confidence_description, timestamp=getDateFromTimestamp(int(attribute["timestamp"])))
return indicator
# converts timestamp to the format used by STIX
@ -323,6 +318,13 @@ def addJournalEntry(incident, entry_line):
# main
def main(args):
pathname = os.path.dirname(sys.argv[0])
if len(sys.argv) > 3:
namespace[0] = sys.argv[3]
if len(sys.argv) > 4:
namespace[1] = sys.argv[4].replace(" ", "_")
NS_DICT[namespace[0]]=namespace[1]
cybox.utils.idgen.set_id_namespace(Namespace(namespace[0], namespace[1]))
stix.utils.idgen.set_id_namespace({namespace[0]: namespace[1]})
events = loadEvent(args, pathname)
stix_package = generateMainPackage(events)
for event in events: