md5 and sha1 hashes now automatically lowercase

cleaned up some code and fixed some vulnerabilities
pull/61/head
Christophe Vandeplas 2012-03-25 15:56:29 +02:00
parent 86b760cd54
commit 7b1673d212
3 changed files with 181 additions and 197 deletions

View File

@ -13,8 +13,8 @@ class EventsController extends AppController {
* Components
*
* @var array
*/
*/
public $components = array('Security', 'Email');
public $paginate = array(
'limit' => 50,
@ -22,19 +22,19 @@ class EventsController extends AppController {
'Event.date' => 'DESC'
)
);
function beforeFilter() {
// what pages are allowed for non-logged-in users
$this->Auth->allow('xml');
$this->Auth->allow('nids');
$this->Auth->allow('text');
// These variables are required for every view
$this->set('me', $this->Auth->user());
$this->set('isAdmin', $this->_isAdmin());
}
public function isAuthorized($user) {
// Admins can access everything
if (parent::isAuthorized($user)) {
@ -45,10 +45,10 @@ class EventsController extends AppController {
$eventid = $this->request->params['pass'][0];
return $this->Event->isOwnedByOrg($eventid, $this->Auth->user('org'));
}
// the other pages are allowed by logged in users
// the other pages are allowed by logged in users
return true;
}
/**
* index method
*
@ -77,14 +77,14 @@ class EventsController extends AppController {
}
$this->set('event', $this->Event->read(null, $id));
$this->set('relatedEvents', $this->Event->getRelatedEvents());
$related_signatures = array();
$this->loadModel('Signature');
foreach ($this->Event->data['Signature'] as $signature) {
$related_signatures[$signature['id']] = $this->Signature->getRelatedSignatures($signature);
}
$this->set('relatedSignatures', $related_signatures);
$this->set('categories', $this->Signature->validate['category']['rule'][1]);
}
@ -124,12 +124,8 @@ class EventsController extends AppController {
if (!$this->Event->exists()) {
throw new NotFoundException(__('Invalid event'));
}
// Replaced by isAuthorized
// // only edit own events
// $old_event = $this->Event->read(null, $id);
// if (!$this->_isAdmin() && $this->Auth->user('org') != $old_event['Event']['org']) {
// throw new UnauthorizedException('You are only allowed to edit events of your own organisation.');
// }
// only edit own events verified by isAuthorized
if ($this->request->is('post') || $this->request->is('put')) {
// always force the user and org, but do not force it for admins
if (!$this->_isAdmin()) {
@ -141,7 +137,7 @@ class EventsController extends AppController {
}
// we probably also want to remove the alerted flag
$this->request->data['Event']['alerted'] = 0;
// say what fields are to be updated
$fieldList=array('user_id', 'org', 'date', 'risk', 'info', 'alerted', 'private');
if ($this->Event->save($this->request->data, true, $fieldList)) {
@ -153,7 +149,7 @@ class EventsController extends AppController {
} else {
$this->request->data = $this->Event->read(null, $id);
}
// combobox for types
$risks = $this->Event->validate['risk']['rule'][1];
$risks = $this->_arrayToValuesIndexArray($risks);
@ -174,12 +170,8 @@ class EventsController extends AppController {
if (!$this->Event->exists()) {
throw new NotFoundException(__('Invalid event'));
}
// Replaced by isAuthorized
// // only edit own events
// $this->Event->read();
// if (!$this->_isAdmin() && $this->Auth->user('org') != $this->Event->data['Event']['org']) {
// throw new UnauthorizedException('You are only allowed to edit your own events.');
// }
// only edit own events verified by isAuthorized
if ($this->Event->delete()) {
$this->Session->setFlash(__('Event deleted'));
$this->redirect(array('action' => 'index'));
@ -197,25 +189,21 @@ class EventsController extends AppController {
if (!$this->Event->exists()) {
throw new NotFoundException(__('Invalid event'));
}
// only allow form submit CSRF protection.
if ($this->request->is('post') || $this->request->is('put')) {
$this->Event->id = $id;
$this->Event->read();
// Replaced by isAuthorized
// // only allow alert for own events or admins
// if (!$this->_isAdmin() && $this->Auth->user('org') != $this->Event->data['Event']['org']) {
// throw new UnauthorizedException('You are only allowed to finish events of your own organisation.');
// }
// only allow alert for own events verified by isAuthorized
// fetch the event and build the body
if (1 == $this->Event->data['Event']['alerted']) {
$this->Session->setFlash(__('Everyone has already been alerted for this event. To alert again, first edit this event.', true), 'default', array(), 'error');
$this->redirect(array('action' => 'view', $id));
}
// The mail body, Sanitize::html() is NOT needed as we are sending plain-text mails.
$body = "";
$appendlen = 20;
@ -230,7 +218,7 @@ class EventsController extends AppController {
if (!empty($relatedEvents)) {
foreach ($relatedEvents as $relatedEvent){
$body .= 'Related to : '.Configure::read('CyDefSIG.baseurl').'/events/view/'.$relatedEvent['Event']['id'].' ('.$relatedEvent['Event']['date'].')'."\n" ;
}
}
$body .= 'Info : '."\n";
@ -238,7 +226,7 @@ class EventsController extends AppController {
$body .= "\n";
$body .= 'Attributes :'."\n";
$body_temp_other = "";
if (isset($this->Event->data['Signature'])) {
foreach ($this->Event->data['Signature'] as $signature){
$line = '- '.$signature['type'].str_repeat(' ', $appendlen - 2 - strlen( $signature['type'])).': '.$signature['value']."\n";
@ -249,15 +237,15 @@ class EventsController extends AppController {
}
$body .= "\n";
$body .= $body_temp_other; // append the 'other' attribute types to the bottom.
// sign the body
require_once 'Crypt/GPG.php';
$gpg = new Crypt_GPG(array('homedir' => Configure::read('GnuPG.homedir')));
$gpg->addSignKey(Configure::read('GnuPG.email'), Configure::read('GnuPG.password'));
$body_signed = $gpg->sign($body, Crypt_GPG::SIGN_MODE_CLEAR);
$this->loadModel('User');
//
// Build a list of the recipients that get a non-encrypted mail
// But only do this if it is allowed in the bootstrap.php file.
@ -286,7 +274,7 @@ class EventsController extends AppController {
// to reset the email fields using the reset method of the Email component.
$this->Email->reset();
}
//
// Build a list of the recipients that wish to receive encrypted mails.
//
@ -304,34 +292,34 @@ class EventsController extends AppController {
$this->Email->subject = "[CyDefSIG] Event ".$id." - ".$this->Event->data['Event']['risk']." - TLP Amber";
$this->Email->template = 'body';
$this->Email->sendAs = 'text'; // both text or html
// import the key of the user into the keyring
// this is not really necessary, but it enables us to find
// this is not really necessary, but it enables us to find
// the correct key-id even if it is not the same as the emailaddress
$key_import_output = $gpg->importKey($user['User']['gpgkey']);
// say what key should be used to encrypt
$gpg = new Crypt_GPG();
$gpg->addEncryptKey($key_import_output['fingerprint']); // use the key that was given in the import
$body_enc_sig = $gpg->encrypt($body_signed, true);
$this->set('body', $body_enc_sig);
$this->Email->send();
// If you wish to send multiple emails using a loop, you'll need
// to reset the email fields using the reset method of the Email component.
$this->Email->reset();
}
// update the DB to set the alerted flag
$this->Event->saveField('alerted', 1);
// redirect to the view event page
$this->Session->setFlash(__('Email sent to all participants.', true));
$this->redirect(array('action' => 'view', $id));
}
}
/**
* Send out an contact email to the person who posted the event.
* Users with a GPG key will get the mail encrypted, other users will get the mail unencrypted
@ -341,12 +329,12 @@ class EventsController extends AppController {
if (!$this->Event->exists()) {
throw new NotFoundException(__('Invalid event'));
}
// User has filled in his contact form, send out the email.
if ($this->request->is('post') || $this->request->is('put')) {
$message = $this->request->data['Event']['message'];
if ($this->_sendContactEmail($id, $message)) {
// LATER when a user is deleted this will create problems.
// LATER when a user is deleted this will create problems.
// LATER send the email to all the people who are in the org that created the event
// redirect to the view event page
$this->Session->setFlash(__('Email sent to the reporter.', true));
@ -360,8 +348,8 @@ class EventsController extends AppController {
$this->data = $this->Event->read(null, $id);
}
}
/**
*
* Sends out an email with the request to be contacted about a specific event.
@ -391,7 +379,7 @@ class EventsController extends AppController {
$body .="\n";
$body .="\n";
$body .="The event is the following: \n";
// print the event in mail-format
// LATER place event-to-email-layout in a function
$appendlen = 20;
@ -406,7 +394,7 @@ class EventsController extends AppController {
if (!empty($relatedEvents)) {
foreach ($relatedEvents as $relatedEvent){
$body .= 'Related to : '.Configure::read('CyDefSIG.baseurl').'/events/view/'.$relatedEvent['Event']['id'].' ('.$relatedEvent['Event']['date'].')'."\n" ;
}
}
$body .= 'Info : '."\n";
@ -430,7 +418,7 @@ class EventsController extends AppController {
$gpg = new Crypt_GPG(array('homedir' => Configure::read('GnuPG.homedir')));
$gpg->addSignKey(Configure::read('GnuPG.email'), Configure::read('GnuPG.password'));
$body_signed = $gpg->sign($body, Crypt_GPG::SIGN_MODE_CLEAR);
if (!empty($reporter['gpgkey'])) {
// import the key of the user into the keyring
// this isn't really necessary, but it gives it the fingerprint necessary for the next step
@ -438,7 +426,7 @@ class EventsController extends AppController {
// say what key should be used to encrypt
$gpg = new Crypt_GPG();
$gpg->addEncryptKey($key_import_output['fingerprint']); // use the key that was given in the import
$body_enc_sig = $gpg->encrypt($body_signed, true);
} else {
$body_enc_sig = $body_signed;
@ -453,7 +441,7 @@ class EventsController extends AppController {
$this->Email->template = 'body';
$this->Email->sendAs = 'text'; // both text or html
$this->set('body', $body_enc_sig);
// Add the GPG key of the user as attachment
// LATER sign the attached GPG key
if (!empty($me_user['gpgkey'])) {
@ -467,28 +455,28 @@ class EventsController extends AppController {
'gpgkey.asc' => $tmpfname
);
}
// send it
$result = $this->Email->send();
// remove the temporary gpg file
if (!empty($me_user['gpgkey']))
unlink($tmpfname);
return $result;
}
public function export() {
// Simply display a static view
// generate the list of Attribute types
$this->loadModel('Signature');
$this->set('sig_types', $this->Signature->validate['type']['rule'][1]);
}
public function xml($key) {
// FIXME implement XML output
// check if the key is valid -> search for users based on key
@ -502,7 +490,7 @@ class EventsController extends AppController {
$this->header('Content-Type: text/xml'); // set the content type
$this->layout = 'xml/default';
// $this->header('Content-Disposition: attachment; filename="cydefsig.xml"');
$conditions = array("Event.alerted" => 1);
$fields = array('Event.id', 'Event.date', 'Event.risk', 'Event.info');
if ('true' == Configure::read('CyDefSIG.showorg')) {
@ -516,14 +504,14 @@ class EventsController extends AppController {
// 'contain' => $contain
);
$results = $this->Event->find('all', $params);
/* $xml = Xml::build('<?xml version="1.0" encoding="UTF-8" ?><CyDefSIG></CyDefSIG>'); */
$myXmlOriginal = '<?xml version="1.0"?><root><child>value</child></root>';
$xml = Xml::build($myXmlOriginal);
$xml->root->addChild('young', 'new value');
// foreach ($results as $result) {
// debug($result);
// $xml->CyDefSIG->addChild('f', 'b');
@ -534,8 +522,8 @@ class EventsController extends AppController {
// debug($xml->saveXML());
}
public function nids($key) {
// check if the key is valid -> search for users based on key
$this->loadModel('User');
@ -548,24 +536,24 @@ class EventsController extends AppController {
$this->header('Content-Type: text/plain'); // set the content type
$this->header('Content-Disposition: attachment; filename="cydefsig.rules"');
$this->layout = 'text/default';
$rules= array();
// find events that are published
$events = $this->Event->findAllByAlerted(1);
$classtype = 'targeted-attack';
foreach ($events as $event) {
# proto src_ip src_port direction dst_ip dst_port msg rule_content tag sid rev
$rule_format_msg = 'msg: "CyDefSIG %s, Event '.$event['Event']['id'].', '.$event['Event']['risk'].'"';
$rule_format_reference = 'reference:url,'.Configure::read('CyDefSIG.baseurl').'/events/view/'.$event['Event']['id'];
$rule_format = 'alert %s %s %s %s %s %s ('.$rule_format_msg.'; %s %s classtype:'.$classtype.'; sid:%d; rev:%d; '.$rule_format_reference.';) ';
$sid = $user['User']['nids_sid']+($event['Event']['id']*100); // LATER this will cause issues with events containing more than 99 attributes
//debug($event);
foreach ($event['Signature'] as $signature) {
if (0 == $signature['to_ids']) continue; // attribute is not to be exported to IDS. // LATER filter out to_ids=0 in the query
$sid++;
switch ($signature['type']) {
// LATER test all the snort signatures
@ -714,7 +702,7 @@ class EventsController extends AppController {
break;
case 'snort':
$tmp_rule = $signature['value'];
// rebuild the rule by overwriting the different keywords using preg_replace()
// sid - '/sid\s*:\s*[0-9]+\s*;/'
// rev - '/rev\s*:\s*[0-9]+\s*;/'
@ -733,7 +721,7 @@ class EventsController extends AppController {
if (null == $tmp_rule ) break; // don't output the rule on error with the regex
$tmp_rule = preg_replace('/reference\s*:\s*.+;/', $rule_format_reference.';', $tmp_rule, -1, $replace_count['reference']);
if (null == $tmp_rule ) break; // don't output the rule on error with the regex
// some values were not replaced, so we need to add them ourselves, and insert them in the rule
$extra_for_rule="";
if (0 == $replace_count['sid']) {
@ -748,15 +736,15 @@ class EventsController extends AppController {
$extra_for_rule .= $rule_format_reference.';';
}
$tmp_rule = preg_replace('/;\s*\)/', '; '.$extra_for_rule.')', $tmp_rule);
// finally the rule is cleaned up and can be outputed
$rules[] = $tmp_rule;
// TODO test using lots of snort rules.
default:
break;
}
}
}
@ -768,10 +756,10 @@ class EventsController extends AppController {
print "#</pre>\n";
$this->set('rules', $rules);
}
public function text($key, $type="") {
// check if the key is valid -> search for users based on key
$this->loadModel('User');
@ -780,10 +768,10 @@ class EventsController extends AppController {
if (empty($user)) {
throw new UnauthorizedException('Incorrect authentication key');
}
$this->header('Content-Type: text/plain'); // set the content type
$this->layout = 'text/default';
$this->loadModel('Signature');
$params = array(
'conditions' => array('Signature.type' => $type), //array of conditions
@ -793,11 +781,11 @@ class EventsController extends AppController {
'group' => array('Signature.value'), //fields to GROUP BY
);
$signatures = $this->Signature->find('all', $params);
$this->set('signatures', $signatures);
}
/**
* // LATER move _dnsNameToRawFormat($name) function to a better place
* Converts a DNS name to a raw format usable in NIDS like Snort.
@ -823,7 +811,7 @@ class EventsController extends AppController {
// and append |00| to terminate the name
return $rawName;
}
}

View File

@ -11,18 +11,18 @@ App::uses('File', 'Utility');
class SignaturesController extends AppController {
public $components = array('Security');
function beforeFilter() {
// permit reuse of CSRF tokens on the search page.
// permit reuse of CSRF tokens on the search page.
if ('search' == $this->request->params['action']) {
$this->Security->csrfUseOnce = false;
}
// These variables are required for every view
$this->set('me', $this->Auth->user());
$this->set('isAdmin', $this->_isAdmin());
}
public function isAuthorized($user) {
// Admins can access everything
@ -43,7 +43,7 @@ class SignaturesController extends AppController {
// the other pages are allowed by logged in users
return true;
}
/**
* index method
*
@ -62,13 +62,7 @@ class SignaturesController extends AppController {
public function add($event_id = null) {
if ($this->request->is('post')) {
$this->loadModel('Event');
// Replaced by isAuthorized
// // only own signatures
// $this->Event->recursive = 0;
// $event = $this->Event->findById($this->request->data['Signature']['event_id']);
// if (!$this->_isAdmin() && $this->Auth->user('org') != $event['Event']['org']) {
// throw new UnauthorizedException('You can only add signatures for your own organisation.');
// }
// only own signatures verified by isAuthorized
// Give error if someone tried to submit a signature with attachment or malware-sample type.
// FIXME this is bad ... it should rather by a messagebox or should be filtered out on the view level
@ -77,26 +71,26 @@ class SignaturesController extends AppController {
$this->Session->setFlash(__('Attribute has not been added: attachments are added by "Add attachment" button', true), 'default', array(), 'error');
$this->redirect(array('controller' => 'events', 'action' => 'view', $this->request->data['Signature']['event_id']));
}
// remove the alerted flag from the event
$this->Event->id = $this->request->data['Signature']['event_id'];
$this->Event->saveField('alerted', 0);
//
// multiple signatures in batch import
//
if ($this->request->data['Signature']['batch_import'] == 1) {
// make array from value field
$signatures = explode("\n", $this->request->data['Signature']['value']);
$fails = ""; // will be used to keep a list of the lines that failed or succeeded
$successes = "";
foreach ($signatures as $key => $signature) {
$signature = trim($signature);
if (strlen($signature) == 0 )
continue; // don't do anything for empty lines
$this->Signature->create();
$this->request->data['Signature']['value'] = $signature; // set the value as the content of the single line
$this->request->data['Signature']['uuid'] = String::uuid();
@ -105,7 +99,7 @@ class SignaturesController extends AppController {
} else {
$fails .= " ".($key+1);
}
}
// we added all the signatures,
if ($fails) {
@ -116,11 +110,11 @@ class SignaturesController extends AppController {
// list the ones that succeeded
$this->Session->setFlash(__('The lines'.$successes.' have been saved', true));
}
$this->redirect(array('controller' => 'events', 'action' => 'view', $this->request->data['Signature']['event_id']));
}
else {
//
// single signature
@ -128,7 +122,7 @@ class SignaturesController extends AppController {
// create the signature
$this->Signature->create();
$this->request->data['Signature']['uuid'] = String::uuid();
if ($this->Signature->save($this->request->data)) {
// inform the user and redirect
$this->Session->setFlash(__('The attribute has been saved'));
@ -141,7 +135,7 @@ class SignaturesController extends AppController {
// set the event_id in the form
$this->request->data['Signature']['event_id'] = $event_id;
}
// combobox for types
$types = $this->Signature->validate['type']['rule'][1];
$types = $this->_arrayToValuesIndexArray($types);
@ -151,14 +145,14 @@ class SignaturesController extends AppController {
$categories = $this->_arrayToValuesIndexArray($categories);
$this->set('categories',compact('categories'));
}
public function download($id = null) {
$this->Signature->id = $id;
if (!$this->Signature->exists()) {
throw new NotFoundException(__('Invalid signature'));
}
$this->Signature->read();
$file = new File(APP.DS."files".DS.$this->Signature->data['Signature']['event_id'].DS.$this->Signature->data['Signature']['id']);
$filename = '';
@ -170,18 +164,18 @@ class SignaturesController extends AppController {
} else {
throw new NotFoundException(__('Signature not an attachment or malware-sample'));
}
$file_ext = explode(".", $filename);
$this->viewClass = 'Media';
$params = array(
'id' => $file->path,
'name' => $filename,
'name' => $filename,
'download' => true,
'path' => DS
);
$this->set($params);
}
/**
* add_attachment method
*
@ -190,16 +184,11 @@ class SignaturesController extends AppController {
public function add_attachment($event_id = null) {
if ($this->request->is('post')) {
$this->loadModel('Event');
// // Replaced by isAuthorized
// // // only own signatures
// // $this->Event->recursive = 0;
// // $event = $this->Event->findById($this->request->data['Signature']['event_id']);
// // if (!$this->_isAdmin() && $this->Auth->user('org') != $event['Event']['org']) {
// // throw new UnauthorizedException('You can only add signatures for your own organisation.');
// // }
// only own signatures verified by isAuthorized
// Check if there were problems with the file upload
$filename = Sanitize::HTML($this->request->data['Signature']['value']['name']);
// only keep the last part of the filename, this should prevent directory attacks
$filename = basename($this->request->data['Signature']['value']['name']);
$tmpfile = new File($this->request->data['Signature']['value']['tmp_name']);
if ((isset($this->request->data['Signature']['value']['error']) && $this->request->data['Signature']['value']['error'] == 0) ||
(!empty( $this->request->data['Signature']['value']['tmp_name']) && $this->request->data['Signature']['value']['tmp_name'] != 'none')
@ -210,11 +199,11 @@ class SignaturesController extends AppController {
$this->Session->setFlash(__('There was a problem to upload the file.', true), 'default', array(), 'error');
$this->redirect(array('controller' => 'events', 'action' => 'view', $this->request->data['Signature']['event_id']));
}
// remove the alerted flag from the event
$this->Event->id = $this->request->data['Signature']['event_id'];
$this->Event->saveField('alerted', 0);
// save the file-info in the database
$this->Signature->create();
if($this->request->data['Signature']['malware']) {
@ -228,14 +217,14 @@ class SignaturesController extends AppController {
$this->request->data['Signature']['uuid'] = String::uuid();
$this->request->data['Signature']['to_ids'] = 0; // LATER permit user to send this to IDS
$this->request->data['Signature']['batch_import'] = 0;
if ($this->Signature->save($this->request->data)) {
// signature saved correctly in the db
} else {
$this->Session->setFlash(__('The attribute could not be saved. Did you already upload this file?'));
$this->redirect(array('controller' => 'events', 'action' => 'view', $this->request->data['Signature']['event_id']));
}
// no errors in file upload, entry already in db, now move the file where needed and zip it if required.
// no sanitization is required on the filename, path or type as we save
// create directory structure
@ -245,8 +234,8 @@ class SignaturesController extends AppController {
$destpath = $root_dir.DS.$this->Signature->id; // id of the new signature in the database
$file = new File ($destpath);
$zipfile = new File ($destpath.'.zip');
$file_in_zip = new File($root_dir.DS.$filename); // FIXME do sanitization of the filename
$file_in_zip = new File($root_dir.DS.$filename); // FIXME do sanitization of the filename
if($file->exists() || $zipfile->exists() || $file_in_zip->exists()) {
// this should never happen as the signature id should be unique
$this->Session->setFlash(__('Attachment with this name already exist in this event.', true), 'default', array(), 'error');
@ -265,10 +254,10 @@ class SignaturesController extends AppController {
if($this->request->data['Signature']['malware']) {
// TODO check if CakePHP has no easy/safe wrapper to execute commands
$exec_retval = ''; $exec_output = array();
rename($file->path, $file_in_zip->path); // FIXME prevent any attacks
rename($file->path, $file_in_zip->path); // TODO check if no workaround exists for the current filtering mechanisms
exec("zip -j -P infected ".$zipfile->path.' "'.addslashes($file_in_zip->path).'"', $exec_output, $exec_retval);
if($exec_retval != 0) { // not EXIT_SUCCESS
$this->Session->setFlash(__('Problem with zipping the attachment. Please report to administrator. ', true), 'default', array(), 'error');
if($exec_retval != 0) { // not EXIT_SUCCESS
$this->Session->setFlash(__('Problem with zipping the attachment. Please report to administrator. '.$exec_output, true), 'default', array(), 'error');
// remove the entry from the database
$this->Signature->delete();
$file_in_zip->delete();
@ -278,16 +267,16 @@ class SignaturesController extends AppController {
$file_in_zip->delete(); // delete the original not-zipped-file
rename($zipfile->path, $file->path); // rename the .zip to .nothing
}
// everything is done, now redirect to event view
$this->Session->setFlash(__('The attachment has been uploaded'));
$this->redirect(array('controller' => 'events', 'action' => 'view', $this->request->data['Signature']['event_id']));
} else {
// set the event_id in the form
$this->request->data['Signature']['event_id'] = $event_id;
}
// combobos for categories
$categories = $this->Signature->validate['category']['rule'][1];
$categories = $this->_arrayToValuesIndexArray($categories);
@ -305,12 +294,7 @@ class SignaturesController extends AppController {
if (!$this->Signature->exists()) {
throw new NotFoundException(__('Invalid signature'));
}
// Replaced by isAuthorized
// // only own signatures
// $this->Signature->read();
// if (!$this->_isAdmin() && $this->Auth->user('org') != $this->Signature->data['Event']['org']) {
// throw new UnauthorizedException('You can only edit signatures from your own organisation.');
// }
// only own signatures verified by isAuthorized
$this->Signature->read();
$event_id = $this->Signature->data['Signature']['event_id'];
@ -323,15 +307,13 @@ class SignaturesController extends AppController {
} else {
$this->set('attachment', false);
}
debug($this->Signature->data);
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->Signature->save($this->request->data)) {
// TODO should I check here if it's possible to change the event_id or org ?
// say what fields are to be updated
$fieldList=array('category', 'type', 'value', 'to_ids');
if ($this->Signature->save($this->request->data, true, $fieldList)) {
$this->Session->setFlash(__('The attribute has been saved'));
debug($this->request->data);
$this->redirect(array('controller' => 'events', 'action' => 'view', $event_id));
} else {
$this->Session->setFlash(__('The attribute could not be saved. Please, try again.'));
@ -365,60 +347,55 @@ class SignaturesController extends AppController {
if (!$this->Signature->exists()) {
throw new NotFoundException(__('Invalid attribute'));
}
// Replaced by isAuthorized
// // only own signatures
// $this->Signature->read();
// if (!$this->_isAdmin() && $this->Auth->user('org') != $this->Signature->data['Event']['org']) {
// throw new UnauthorizedException('You can only delete signatures from your own organisation.');
// }
// only own signatures verified by isAuthorized
// attachment will be deleted with the beforeDelete() function in the Model
if ($this->Signature->delete()) {
$this->Session->setFlash(__('Attribute deleted'));
} else {
$this->Session->setFlash(__('Attribute was not deleted'));
}
$this->redirect($this->referer());
}
public function search() {
if ($this->request->is('post')) {
$keyword = $this->request->data['Signature']['keyword'];
$type = $this->request->data['Signature']['type'];
$category = $this->request->data['Signature']['category'];
// search the db
$conditions = array();
if($keyword) {
$conditions['Signature.value LIKE'] = '%'.$keyword.'%';
}
}
if($type != 'ALL') {
$conditions['Signature.type ='] = $type;
}
}
if($category != 'ALL') {
$conditions['Signature.category ='] = $category;
}
}
$this->Signature->recursive = 0;
$this->paginate = array(
'conditions' => $conditions
);
$this->set('signatures', $this->paginate());
// set the same view as the index page
$this->render('index');
} else {
// no search keyword is given, show the search form
// adding filtering by category and type
// combobox for types
$types = array('ALL');
$types = array_merge($types, $this->Signature->validate['type']['rule'][1]);
$types = $this->_arrayToValuesIndexArray($types);
$this->set('types',compact('types'));
// combobox for categories
$categories = array('ALL');
$categories = array_merge($categories, $this->Signature->validate['category']['rule'][1]);

View File

@ -14,7 +14,7 @@ class Signature extends AppModel {
* @var string
*/
public $displayField = 'value';
var $order = array("Signature.event_id" => "DESC", "Signature.type" => "ASC");
/**
* Validation rules
@ -60,7 +60,7 @@ class Signature extends AppModel {
'required' => true,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
'category' => array(
'rule' => array('inList', array('Payload delivery',
@ -153,17 +153,17 @@ class Signature extends AppModel {
'order' => ''
)
);
function beforeSave() {
// increment the revision number
if (empty($this->data['Signature']['revision'])) $this->data['Signature']['revision'] = 0;
$this->data['Signature']['revision'] = 1 + $this->data['Signature']['revision'] ;
// always return true after a beforeSave()
return true;
}
function beforeDelete() {
// delete attachments from the disk
if('attachment' == $this->data['Signature']['type'] ||
@ -179,38 +179,56 @@ class Signature extends AppModel {
}
}
}
function beforeValidate() {
// remove leading and trailing blanks
$this->data['Signature']['value'] = trim($this->data['Signature']['value']);
switch($this->data['Signature']['type']) {
// lowercase these things
case 'md5':
case 'sha1':
$this->data['Signature']['value'] = strtolower($this->data['Signature']['value']);
break;
}
// always return true, otherwise the object cannot be saved
return true;
}
function validateSignatureValue ($fields) {
$value = $fields['value'];
$event_id = $this->data['Signature']['event_id'];
$type = $this->data['Signature']['type'];
$to_ids = $this->data['Signature']['to_ids'];
$category = $this->data['Signature']['category'];
// check if the signature already exists in the same event
$conditions = array('Signature.event_id' => $event_id,
'Signature.type' => $type,
'Signature.category' => $category,
'Signature.value' => $value
);
if (isset($this->data['Signature']['id']))
$conditions['Signature.id !='] = $this->data['Signature']['id'];
$params = array('recursive' => 0,
'conditions' => array('Signature.event_id' => $event_id,
'Signature.type' => $type,
'Signature.to_ids' => $to_ids,
'Signature.category' => $category,
'Signature.value' => $value),
'conditions' => $conditions,
);
if (0 != $this->find('count', $params) )
return 'Attribute already exists for this event.';
// check data validation
switch($this->data['Signature']['type']) {
// FIXME lowercase hashes
case 'md5':
if (preg_match("#^[0-9a-f]{32}$#", $value))
return true;
return 'Checksum has invalid lenght or format. Please double check the value or select "other" for a type.';
return 'Checksum has invalid length or format. Please double check the value or select "other" for a type.';
break;
case 'sha1':
if (preg_match("#^[0-9a-f]{40}$#", $value))
return true;
return 'Checksum has invalid lenght or format. Please double check the value or select "other" for a type.';
return 'Checksum has invalid length or format. Please double check the value or select "other" for a type.';
break;
case 'filename':
// no newline
@ -220,7 +238,8 @@ class Signature extends AppModel {
case 'filename|md5':
// no newline
if (!preg_match("#^.*|[0-9a-f]{32}$#", $value))
return true;
return true;
return 'Checksum has invalid length or format. Please double check the value or select "other" for a type.';
break;
case 'ip-src':
$parts = explode("/", $value);
@ -307,19 +326,19 @@ class Signature extends AppModel {
return true;
break;
}
// default action is to return false
return true;
}
public function isOwnedByOrg($signatureid, $org) {
$this->id = $signatureid;
$this->read();
return $this->data['Event']['org'] === $org;
}
function getRelatedSignatures($signature) {
// LATER there should be a list of types/categories included here as some are not eligible (AV detection category
// or "other" type could be excluded)
@ -329,12 +348,12 @@ class Signature extends AppModel {
'Signature.type =' => $signature['type'], );
// $fields = array('Event.*');
$fields = array('Signature.*');
$similar_events = $this->find('all',array('conditions' => $conditions,
'fields' => $fields,
'order' => 'Signature.event_id DESC', )
);
return $similar_events;
}
}