2012-03-15 15:06:45 +01:00
< ? php
2012-09-24 16:02:01 +02:00
2012-03-15 15:06:45 +01:00
App :: uses ( 'AppModel' , 'Model' );
2012-05-22 13:58:37 +02:00
App :: uses ( 'Folder' , 'Utility' );
2012-03-23 20:04:22 +01:00
App :: uses ( 'File' , 'Utility' );
2015-07-06 18:19:51 +02:00
App :: uses ( 'FinancialTool' , 'Tools' );
2016-08-25 20:19:16 +02:00
App :: uses ( 'RandomTool' , 'Tools' );
2012-03-23 20:04:22 +01:00
2012-03-26 19:56:44 +02:00
class Attribute extends AppModel {
2012-06-28 17:24:12 +02:00
2012-09-24 16:02:01 +02:00
public $combinedKeys = array ( 'event_id' , 'category' , 'type' );
public $name = 'Attribute' ; // TODO general
2012-09-20 11:34:41 +02:00
2013-01-10 15:43:37 +01:00
public $actsAs = array (
'SysLogLogable.SysLogLogable' => array ( // TODO Audit, logable
'userModel' => 'User' ,
'userKey' => 'user_id' ,
'change' => 'full' ),
'Trim' ,
2013-02-28 17:16:52 +01:00
'Containable' ,
2013-07-04 15:45:11 +02:00
'Regexp' => array ( 'fields' => array ( 'value' )),
2012-11-26 15:34:54 +01:00
);
2012-09-20 11:34:41 +02:00
2012-03-15 15:06:45 +01:00
public $displayField = 'value' ;
2012-03-25 15:56:29 +02:00
2012-04-25 13:17:44 +02:00
public $virtualFields = array (
2016-07-11 20:24:03 +02:00
'value' => " CASE WHEN Attribute.value2 = '' THEN Attribute.value1 ELSE CONCAT(Attribute.value1, '|', Attribute.value2) END " ,
2013-02-04 17:55:35 +01:00
); // TODO hardcoded
2012-04-25 13:17:44 +02:00
2016-08-25 11:38:37 +02:00
// explanations of certain fields to be used in various views
2012-09-19 11:05:10 +02:00
public $fieldDescriptions = array (
2012-05-29 16:53:50 +02:00
'signature' => array ( 'desc' => 'Is this attribute eligible to automatically create an IDS signature (network IDS or host IDS) out of it ?' ),
2013-06-10 17:33:03 +02:00
'distribution' => array ( 'desc' => 'Describes who will have access to the event.' )
2012-05-29 16:53:50 +02:00
);
2012-05-30 10:24:57 +02:00
2012-10-23 11:28:39 +02:00
public $distributionDescriptions = array (
2016-10-02 12:46:30 +02:00
0 => array ( 'desc' => 'This field determines the current distribution of the event' , 'formdesc' => " This setting will only allow members of your organisation on this server to see it. " ),
1 => array ( 'desc' => 'This field determines the current distribution of the event' , 'formdesc' => " Organisations that are part of this MISP community will be able to see the event. " ),
2 => array ( 'desc' => 'This field determines the current distribution of the event' , 'formdesc' => " Organisations that are either part of this MISP community or part of a directly connected MISP community will be able to see the event. " ),
3 => array ( 'desc' => 'This field determines the current distribution of the event' , 'formdesc' => " This will share the event with all MISP communities, allowing the event to be freely propagated from one server to the next. " ),
4 => array ( 'desc' => 'This field determines the current distribution of the event' , 'formdesc' => " This distribution of this event will be handled by the selected sharing group. " ),
5 => array ( 'desc' => 'This field determines the current distribution of the event' , 'formdesc' => " Inherit the event's distribution settings " ),
2013-06-10 20:49:31 +02:00
);
2013-06-12 16:50:21 +02:00
2013-06-24 15:13:33 +02:00
public $distributionLevels = array (
2015-04-14 18:11:51 +02:00
0 => 'Your organisation only' , 1 => 'This community only' , 2 => 'Connected communities' , 3 => 'All communities' , 4 => 'Sharing group' , 5 => 'Inherit event'
2012-10-23 11:28:39 +02:00
);
2016-06-04 01:08:16 +02:00
2015-11-12 09:26:29 +01:00
public $shortDist = array ( 0 => 'Organisation' , 1 => 'Community' , 2 => 'Connected' , 3 => 'All' , 4 => ' sharing Group' , 5 => 'Inherit' );
2012-10-23 11:28:39 +02:00
2016-05-20 04:59:33 +02:00
// these are definitions of possible types + their descriptions and maybe later other behaviors
2012-05-29 16:53:50 +02:00
// e.g. if the attribute should be correlated with others or not
2012-05-30 10:24:57 +02:00
2016-05-20 04:59:33 +02:00
// if these then a category may have upload to be zipped
2012-09-19 11:05:10 +02:00
public $zippedDefinitions = array (
2012-07-10 11:39:43 +02:00
'malware-sample'
);
2016-05-20 04:59:33 +02:00
// if these then a category may have upload
2012-09-19 11:05:10 +02:00
public $uploadDefinitions = array (
2012-07-10 11:39:43 +02:00
'attachment'
2012-07-06 13:48:17 +02:00
);
2016-06-04 01:08:16 +02:00
2015-02-16 13:30:15 +01:00
// skip Correlation for the following types
public $nonCorrelatingTypes = array (
'vulnerability' ,
'comment' ,
2015-11-09 12:36:49 +01:00
'http-method' ,
'aba-rtn'
2015-02-16 13:30:15 +01:00
);
2012-07-06 13:48:17 +02:00
2012-09-19 11:05:10 +02:00
public $typeDefinitions = array (
2016-09-20 00:22:06 +02:00
'md5' => array ( 'desc' => 'A checksum in md5 format' , 'formdesc' => " You are encouraged to use filename|md5 instead. A checksum in md5 format, only use this if you don't know the correct filename " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'sha1' => array ( 'desc' => 'A checksum in sha1 format' , 'formdesc' => " You are encouraged to use filename|sha1 instead. A checksum in sha1 format, only use this if you don't know the correct filename " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'sha256' => array ( 'desc' => 'A checksum in sha256 format' , 'formdesc' => " You are encouraged to use filename|sha256 instead. A checksum in sha256 format, only use this if you don't know the correct filename " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'filename' => array ( 'desc' => 'Filename' , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'pdb' => array ( 'desc' => 'Microsoft Program database (PDB) path information' , 'default_category' => 'Artifacts dropped' , 'to_ids' => 0 ),
'filename|md5' => array ( 'desc' => 'A filename and an md5 hash separated by a |' , 'formdesc' => " A filename and an md5 hash separated by a | (no spaces) " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'filename|sha1' => array ( 'desc' => 'A filename and an sha1 hash separated by a |' , 'formdesc' => " A filename and an sha1 hash separated by a | (no spaces) " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'filename|sha256' => array ( 'desc' => 'A filename and an sha256 hash separated by a |' , 'formdesc' => " A filename and an sha256 hash separated by a | (no spaces) " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'ip-src' => array ( 'desc' => " A source IP address of the attacker " , 'default_category' => 'Network activity' , 'to_ids' => 1 ),
'ip-dst' => array ( 'desc' => 'A destination IP address of the attacker or C&C server' , 'formdesc' => " A destination IP address of the attacker or C&C server. Also set the IDS flag on when this IP is hardcoded in malware " , 'default_category' => 'Network activity' , 'to_ids' => 1 ),
'hostname' => array ( 'desc' => 'A full host/dnsname of an attacker' , 'formdesc' => " A full host/dnsname of an attacker. Also set the IDS flag on when this hostname is hardcoded in malware " , 'default_category' => 'Network activity' , 'to_ids' => 1 ),
'domain' => array ( 'desc' => 'A domain name used in the malware' , 'formdesc' => " A domain name used in the malware. Use this instead of hostname when the upper domain is important or can be used to create links between events. " , 'default_category' => 'Network activity' , 'to_ids' => 1 ),
'domain|ip' => array ( 'desc' => 'A domain name and its IP address (as found in DNS lookup) separated by a |' , 'formdesc' => " A domain name and its IP address (as found in DNS lookup) separated by a | (no spaces) " , 'default_category' => 'Network activity' , 'to_ids' => 1 ),
'email-src' => array ( 'desc' => " The email address (or domainname) used to send the malware. " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'email-dst' => array ( 'desc' => " A recipient email address " , 'formdesc' => " A recipient email address that is not related to your constituency. " , 'default_category' => 'Network activity' , 'to_ids' => 1 ),
'email-subject' => array ( 'desc' => " The subject of the email " , 'default_category' => 'Payload delivery' , 'to_ids' => 0 ),
'email-attachment' => array ( 'desc' => " File name of the email attachment. " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'url' => array ( 'desc' => 'url' , 'default_category' => 'External analysis' , 'to_ids' => 1 ),
'http-method' => array ( 'desc' => " HTTP method used by the malware (e.g. POST, GET, ...). " , 'default_category' => 'Network activity' , 'to_ids' => 0 ),
'user-agent' => array ( 'desc' => " The user-agent used by the malware in the HTTP request. " , 'default_category' => 'Network activity' , 'to_ids' => 0 ),
'regkey' => array ( 'desc' => " Registry key or value " , 'default_category' => 'Persistence mechanism' , 'to_ids' => 1 ),
'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 ),
'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 ),
'yara' => array ( 'desc' => 'Yara signature' , 'default_category' => 'Payload installation' , 'to_ids' => 1 ),
'vulnerability' => array ( 'desc' => 'A reference to the vulnerability used in the exploit' , 'default_category' => 'External analysis' , 'to_ids' => 0 ),
'attachment' => array ( 'desc' => 'Attachment with external information' , 'formdesc' => " Please upload files using the <em>Upload Attachment</em> button. " , 'default_category' => 'External analysis' , 'to_ids' => 0 ),
'malware-sample' => array ( 'desc' => 'Attachment containing encrypted malware sample' , 'formdesc' => " Please upload files using the <em>Upload Attachment</em> button. " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'link' => array ( 'desc' => 'Link to an external information' , 'default_category' => 'External analysis' , 'to_ids' => 0 ),
'comment' => array ( 'desc' => 'Comment or description in a human language' , 'formdesc' => 'Comment or description in a human language. This will not be correlated with other attributes' , 'default_category' => 'Other' , 'to_ids' => 0 ),
'text' => array ( 'desc' => 'Name, ID or a reference' , 'default_category' => 'Other' , 'to_ids' => 0 ),
'other' => array ( 'desc' => 'Other attribute' , 'default_category' => 'Other' , 'to_ids' => 0 ),
'named pipe' => array ( 'desc' => 'Named pipe, use the format \\.\pipe\<PipeName>' , 'default_category' => 'Artifacts dropped' , 'to_ids' => 0 ),
'mutex' => array ( 'desc' => 'Mutex, use the format \BaseNamedObjects\<Mutex>' , 'default_category' => 'Artifacts dropped' , 'to_ids' => 1 ),
'target-user' => array ( 'desc' => 'Attack Targets Username(s)' , 'default_category' => 'Targeting data' , 'to_ids' => 0 ),
'target-email' => array ( 'desc' => 'Attack Targets Email(s)' , 'default_category' => 'Targeting data' , 'to_ids' => 0 ),
'target-machine' => array ( 'desc' => 'Attack Targets Machine Name(s)' , 'default_category' => 'Targeting data' , 'to_ids' => 0 ),
'target-org' => array ( 'desc' => 'Attack Targets Department or Organization(s)' , 'default_category' => 'Targeting data' , 'to_ids' => 0 ),
'target-location' => array ( 'desc' => 'Attack Targets Physical Location(s)' , 'default_category' => 'Targeting data' , 'to_ids' => 0 ),
'target-external' => array ( 'desc' => 'External Target Organizations Affected by this Attack' , 'default_category' => 'Targeting data' , 'to_ids' => 0 ),
'btc' => array ( 'desc' => 'Bitcoin Address' , 'default_category' => 'Financial fraud' , 'to_ids' => 1 ),
'iban' => array ( 'desc' => 'International Bank Account Number' , 'default_category' => 'Financial fraud' , 'to_ids' => 1 ),
'bic' => array ( 'desc' => 'Bank Identifier Code Number' , 'default_category' => 'Financial fraud' , 'to_ids' => 1 ),
'bank-account-nr' => array ( 'desc' => 'Bank account number without any routing number' , 'default_category' => 'Financial fraud' , 'to_ids' => 1 ),
'aba-rtn' => array ( 'desc' => 'ABA routing transit number' , 'default_category' => 'Financial fraud' , 'to_ids' => 1 ),
'bin' => array ( 'desc' => 'Bank Identification Number' , 'default_category' => 'Financial fraud' , 'to_ids' => 1 ),
'cc-number' => array ( 'desc' => 'Credit-Card Number' , 'default_category' => 'Financial fraud' , 'to_ids' => 1 ),
'prtn' => array ( 'desc' => 'Premium-Rate Telephone Number' , 'default_category' => 'Financial fraud' , 'to_ids' => 1 ),
'threat-actor' => array ( 'desc' => 'A string identifying the threat actor' , 'default_category' => 'Attribution' , 'to_ids' => 0 ),
'campaign-name' => array ( 'desc' => 'Associated campaign name' , 'default_category' => 'Attribution' , 'to_ids' => 0 ),
'campaign-id' => array ( 'desc' => 'Associated campaign ID' , 'default_category' => 'Attribution' , 'to_ids' => 0 ),
'malware-type' => array ( 'desc' => '' , 'default_category' => 'Payload delivery' , 'to_ids' => 0 ),
'uri' => array ( 'desc' => 'Uniform Resource Identifier' , 'default_category' => 'Network activity' , 'to_ids' => 1 ),
'authentihash' => array ( 'desc' => 'Authenticode executable signature hash' , 'formdesc' => " You are encouraged to use filename|authentihash instead. Authenticode executable signature hash, only use this if you don't know the correct filename " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'ssdeep' => array ( 'desc' => 'A checksum in ssdeep format' , 'formdesc' => " You are encouraged to use filename|ssdeep instead. A checksum in the SSDeep format, only use this if you don't know the correct filename " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'imphash' => array ( 'desc' => 'Import hash - a hash created based on the imports in the sample.' , 'formdesc' => " You are encouraged to use filename|imphash instead. A hash created based on the imports in the sample, only use this if you don't know the correct filename " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'pehash' => array ( 'desc' => 'PEhash - a hash calculated based of certain pieces of a PE executable file' , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'sha224' => array ( 'desc' => 'A checksum in sha-224 format' , 'formdesc' => " You are encouraged to use filename|sha224 instead. A checksum in sha224 format, only use this if you don't know the correct filename " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'sha384' => array ( 'desc' => 'A checksum in sha-384 format' , 'formdesc' => " You are encouraged to use filename|sha384 instead. A checksum in sha384 format, only use this if you don't know the correct filename " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'sha512' => array ( 'desc' => 'A checksum in sha-512 format' , 'formdesc' => " You are encouraged to use filename|sha512 instead. A checksum in sha512 format, only use this if you don't know the correct filename " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'sha512/224' => array ( 'desc' => 'A checksum in the sha-512/224 format' , 'formdesc' => " You are encouraged to use filename|sha512/224 instead. A checksum in sha512/224 format, only use this if you don't know the correct filename " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'sha512/256' => array ( 'desc' => 'A checksum in the sha-512/256 format' , 'formdesc' => " You are encouraged to use filename|sha512/256 instead. A checksum in sha512/256 format, only use this if you don't know the correct filename " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'tlsh' => array ( 'desc' => 'A checksum in the Trend Micro Locality Sensitive Hash format' , 'formdesc' => " You are encouraged to use filename|tlsh instead. A checksum in the Trend Micro Locality Sensitive Hash format, only use this if you don't know the correct filename " , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'filename|authentihash' => array ( 'desc' => 'A checksum in md5 format' , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'filename|ssdeep' => array ( 'desc' => 'A checksum in ssdeep format' , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'filename|imphash' => array ( 'desc' => 'Import hash - a hash created based on the imports in the sample.' , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'filename|pehash' => array ( 'desc' => 'A filename and a PEhash separated by a |' , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'filename|sha224' => array ( 'desc' => 'A filename and a sha-224 hash separated by a |' , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'filename|sha384' => array ( 'desc' => 'A filename and a sha-384 hash separated by a |' , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'filename|sha512' => array ( 'desc' => 'A filename and a sha-512 hash separated by a |' , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'filename|sha512/224' => array ( 'desc' => 'A filename and a sha-512/224 hash separated by a |' , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'filename|sha512/256' => array ( 'desc' => 'A filename and a sha-512/256 hash separated by a |' , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'filename|tlsh' => array ( 'desc' => 'A filename and a Trend Micro Locality Sensitive Hash separated by a |' , 'default_category' => 'Payload delivery' , 'to_ids' => 1 ),
'windows-scheduled-task' => array ( 'desc' => 'A scheduled task in windows' , 'default_category' => 'Artifacts dropped' , 'to_ids' => 0 ),
'windows-service-name' => array ( 'desc' => 'A windows service name. This is the name used internally by windows. Not to be confused with the windows-service-displayname.' , 'default_category' => 'Artifacts dropped' , 'to_ids' => 0 ),
'windows-service-displayname' => array ( 'desc' => 'A windows service\'s displayname, not to be confused with the windows-service-name. This is the name that applications will generally display as the service\'s name in applications.' , 'default_category' => 'Artifacts dropped' , 'to_ids' => 0 ),
'whois-registrant-email' => array ( 'desc' => 'The e-mail of a domain\'s registrant, obtained from the WHOIS information.' , 'default_category' => 'Attribution' , 'to_ids' => 0 ),
'whois-registrant-phone' => array ( 'desc' => 'The phone number of a domain\'s registrant, obtained from the WHOIS information.' , 'default_category' => 'Attribution' , 'to_ids' => 0 ),
'whois-registrant-name' => array ( 'desc' => 'The name of a domain\'s registrant, obtained from the WHOIS information.' , 'default_category' => 'Attribution' , 'to_ids' => 0 ),
'whois-registrar' => array ( 'desc' => 'The registrar of the domain, obtained from the WHOIS information.' , 'default_category' => 'Attribution' , 'to_ids' => 0 ),
'whois-creation-date' => array ( 'desc' => 'The date of domain\'s creation, obtained from the WHOIS information.' , 'default_category' => 'Attribution' , 'to_ids' => 0 ),
// 'targeted-threat-index' => array('desc' => ''), // currently not mapped!
// 'mailslot' => array('desc' => 'MailSlot interprocess communication'), // currently not mapped!
// 'pipe' => array('desc' => 'Pipeline (for named pipes use the attribute type "named pipe")'), // currently not mapped!
// 'ssl-cert-attributes' => array('desc' => 'SSL certificate attributes'), // currently not mapped!
'x509-fingerprint-sha1' => array ( 'desc' => 'X509 fingerprint in SHA-1 format' , 'default_category' => 'Network activity' , 'to_ids' => 1 )
2012-05-29 16:53:50 +02:00
);
2012-05-30 10:24:57 +02:00
2012-05-29 16:53:50 +02:00
// definitions of categories
2012-09-19 11:05:10 +02:00
public $categoryDefinitions = array (
2012-05-30 17:13:35 +02:00
'Internal reference' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Reference used by the publishing party (e.g. ticket number)' ,
2016-09-02 21:32:56 +02:00
'types' => array ( 'text' , 'link' , 'comment' , 'other' )
2012-09-18 15:30:32 +02:00
),
2016-06-04 01:14:25 +02:00
'Targeting data' => array (
'desc' => 'Internal Attack Targeting and Compromise Information' ,
'formdesc' => 'Targeting information to include recipient email, infected machines, department, and or locations.' ,
'types' => array ( 'target-user' , 'target-email' , 'target-machine' , 'target-org' , 'target-location' , 'target-external' , 'comment' )
),
2012-05-30 17:13:35 +02:00
'Antivirus detection' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'All the info about how the malware is detected by the antivirus products' ,
2013-10-30 16:00:46 +01:00
'formdesc' => 'List of anti-virus vendors detecting the malware or information on detection performance (e.g. 13/43 or 67%). Attachment with list of detection or link to VirusTotal could be placed here as well.' ,
2012-09-18 15:30:32 +02:00
'types' => array ( 'link' , 'comment' , 'text' , 'attachment' , 'other' )
),
2012-05-30 17:13:35 +02:00
'Payload delivery' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Information about how the malware is delivered' ,
2013-06-12 16:50:21 +02:00
'formdesc' => 'Information about the way the malware payload is initially delivered, for example information about the email or web-site, vulnerability used, originating IP etc. Malware sample itself should be attached here.' ,
2016-02-13 16:43:41 +01:00
'types' => array ( 'md5' , 'sha1' , 'sha224' , 'sha256' , 'sha384' , 'sha512' , 'sha512/224' , 'sha512/256' , 'ssdeep' , 'imphash' , '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' , 'ip-src' , 'ip-dst' , 'hostname' , 'domain' , 'email-src' , 'email-dst' , 'email-subject' , 'email-attachment' , 'url' , 'user-agent' , 'AS' , 'pattern-in-file' , 'pattern-in-traffic' , 'yara' , 'attachment' , 'malware-sample' , 'link' , 'malware-type' , 'comment' , 'text' , 'vulnerability' , 'x509-fingerprint-sha1' , 'other' )
2012-09-18 15:30:32 +02:00
),
2012-05-30 17:13:35 +02:00
'Artifacts dropped' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Any artifact (files, registry keys etc.) dropped by the malware or other modifications to the system' ,
2016-02-13 16:43:41 +01:00
'types' => array ( 'md5' , 'sha1' , 'sha224' , 'sha256' , 'sha384' , 'sha512' , 'sha512/224' , 'sha512/256' , 'ssdeep' , 'imphash' , 'authentihash' , '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' , 'regkey' , 'regkey|value' , 'pattern-in-file' , 'pattern-in-memory' , 'pdb' , 'yara' , 'attachment' , 'malware-sample' , 'named pipe' , 'mutex' , 'windows-scheduled-task' , 'windows-service-name' , 'windows-service-displayname' , 'comment' , 'text' , 'x509-fingerprint-sha1' , 'other' )
2012-09-18 15:30:32 +02:00
),
2012-05-30 17:13:35 +02:00
'Payload installation' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Info on where the malware gets installed in the system' ,
2013-10-30 16:00:46 +01:00
'formdesc' => 'Location where the payload was placed in the system and the way it was installed. For example, a filename|md5 type attribute can be added here like this: c:\\windows\\system32\\malicious.exe|41d8cd98f00b204e9800998ecf8427e.' ,
2016-02-13 16:43:41 +01:00
'types' => array ( 'md5' , 'sha1' , 'sha224' , 'sha256' , 'sha384' , 'sha512' , 'sha512/224' , 'sha512/256' , 'ssdeep' , 'imphash' , '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' , 'pattern-in-file' , 'pattern-in-traffic' , 'pattern-in-memory' , 'yara' , 'vulnerability' , 'attachment' , 'malware-sample' , 'malware-type' , 'comment' , 'text' , 'x509-fingerprint-sha1' , 'other' )
2012-09-18 15:30:32 +02:00
),
2012-05-30 17:13:35 +02:00
'Persistence mechanism' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Mechanisms used by the malware to start at boot' ,
2013-10-30 16:00:46 +01:00
'formdesc' => 'Mechanisms used by the malware to start at boot. This could be a registry key, legitimate driver modification, LNK file in startup' ,
2012-09-18 15:30:32 +02:00
'types' => array ( 'filename' , 'regkey' , 'regkey|value' , 'comment' , 'text' , 'other' )
),
2012-05-30 17:13:35 +02:00
'Network activity' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Information about network traffic generated by the malware' ,
2016-02-13 16:43:41 +01:00
'types' => array ( 'ip-src' , 'ip-dst' , 'hostname' , 'domain' , 'domain|ip' , 'email-dst' , 'url' , 'uri' , 'user-agent' , 'http-method' , 'AS' , 'snort' , 'pattern-in-file' , 'pattern-in-traffic' , 'attachment' , 'comment' , 'text' , 'x509-fingerprint-sha1' , 'other' )
2012-09-18 15:30:32 +02:00
),
2012-05-30 17:13:35 +02:00
'Payload type' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Information about the final payload(s)' ,
2013-10-30 16:00:46 +01:00
'formdesc' => 'Information about the final payload(s). Can contain a function of the payload, e.g. keylogger, RAT, or a name if identified, such as Poison Ivy.' ,
2012-09-18 15:30:32 +02:00
'types' => array ( 'comment' , 'text' , 'other' )
),
2012-05-30 17:13:35 +02:00
'Attribution' => array (
2012-12-12 16:15:01 +01:00
'desc' => 'Identification of the group, organisation, or country behind the attack' ,
2016-02-26 21:16:46 +01:00
'types' => array ( 'threat-actor' , 'campaign-name' , 'campaign-id' , 'whois-registrant-phone' , 'whois-registrant-email' , 'whois-registrant-name' , 'whois-registrar' , 'whois-creation-date' , 'comment' , 'text' , 'x509-fingerprint-sha1' , 'other' )
2012-09-18 15:30:32 +02:00
),
2012-05-30 17:13:35 +02:00
'External analysis' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Any other result from additional analysis of the malware like tools output' ,
2013-10-30 16:00:46 +01:00
'formdesc' => 'Any other result from additional analysis of the malware like tools output Examples: pdf-parser output, automated sandbox analysis, reverse engineering report.' ,
2016-02-13 16:43:41 +01:00
'types' => array ( 'md5' , 'sha1' , 'sha256' , 'filename' , 'filename|md5' , 'filename|sha1' , 'filename|sha256' , 'ip-src' , 'ip-dst' , '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' , 'other' )
2012-09-18 15:30:32 +02:00
),
2015-07-06 18:19:51 +02:00
'Financial fraud' => array (
'desc' => 'Financial Fraud indicators' ,
'formdesc' => 'Financial Fraud indicators, for example: IBAN Numbers, BIC codes, Credit card numbers, etc.' ,
2015-11-09 12:36:49 +01:00
'types' => array ( 'btc' , 'iban' , 'bic' , 'bank-account-nr' , 'aba-rtn' , 'bin' , 'cc-number' , 'prtn' , 'comment' , 'text' , 'other' ),
2015-07-06 18:19:51 +02:00
),
2012-05-30 17:13:35 +02:00
'Other' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Attributes that are not part of any other category' ,
'types' => array ( 'comment' , 'text' , 'other' )
)
2012-05-29 16:53:50 +02:00
);
2016-06-04 01:08:16 +02:00
2016-02-21 23:11:56 +01:00
public $defaultCategories = array (
'md5' => 'Payload delivery' ,
'sha1' => 'Payload delivery' ,
'sha224' => 'Payload delivery' ,
'sha256' => 'Payload delivery' ,
'sha384' => 'Payload delivery' ,
'sha512' => 'Payload delivery' ,
'sha512/224' => 'Payload delivery' ,
'sha512/256' => 'Payload delivery' ,
'authentihash' => 'Payload delivery' ,
'imphash' => 'Payload delivery' ,
'pehash' => 'Payload delivery' ,
'filename|md5' => 'Payload delivery' ,
'filename|sha1' => 'Payload delivery' ,
'filename|sha256' => 'Payload delivery' ,
'regkey' => 'Persistence mechanism' ,
'filename' => 'Payload delivery' ,
'ip-src' => 'Network activity' ,
'ip-dst' => 'Network activity' ,
'hostname' => 'Network activity' ,
'domain' => 'Network activity' ,
'url' => 'Network activity' ,
'link' => 'External analysis' ,
'email-src' => 'Payload delivery' ,
'email-dst' => 'Payload delivery' ,
'text' => 'Other' ,
2016-03-21 12:08:20 +01:00
'attachment' => 'External analysis' ,
'malware-sample' => 'Payload delivery'
2016-02-21 23:11:56 +01:00
);
2016-06-04 01:08:16 +02:00
2016-01-04 10:23:07 +01:00
// typeGroupings are a mapping to high level groups for attributes
2016-05-20 04:59:33 +02:00
// for example, IP addresses, domain names, hostnames and e-mail addresses are network related attribute types
// whilst filenames and hashes are file related attribute types
2016-06-04 01:10:45 +02:00
// 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?)
2016-01-04 10:23:07 +01:00
public $typeGroupings = array (
2016-02-13 16:43:41 +01:00
'file' => array ( 'attachment' , 'pattern-in-file' , 'md5' , 'sha1' , 'sha224' , 'sha256' , 'sha384' , 'sha512' , 'sha512/224' , 'sha512/256' , 'ssdeep' , 'imphash' , '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' ),
2016-04-23 00:41:50 +02:00
'network' => array ( 'ip-src' , 'ip-dst' , 'hostname' , 'domain' , 'domain|ip' , 'email-dst' , 'url' , 'uri' , 'user-agent' , 'http-method' , 'AS' , 'snort' , 'pattern-in-traffic' , 'x509-fingerprint-sha1' ),
2016-01-04 10:23:07 +01:00
'financial' => array ( 'btc' , 'iban' , 'bic' , 'bank-account-nr' , 'aba-rtn' , 'bin' , 'cc-number' , 'prtn' )
);
2012-05-30 10:24:57 +02:00
2013-06-08 16:55:04 +02:00
public $order = array ( " Attribute.event_id " => " DESC " );
2012-05-30 10:24:57 +02:00
2012-03-15 15:06:45 +01:00
public $validate = array (
'event_id' => array (
'numeric' => array (
'rule' => array ( 'numeric' ),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
'type' => array (
2012-05-29 16:53:50 +02:00
// currently when adding a new attribute type we need to change it in both places
2012-05-31 17:12:26 +02:00
'rule' => array ( 'validateTypeValue' ),
'message' => 'Options depend on the selected category.' ,
2012-03-15 15:06:45 +01:00
//'allowEmpty' => false,
'required' => true ,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
2012-03-25 15:56:29 +02:00
2012-03-15 15:06:45 +01:00
),
2012-09-19 11:05:10 +02:00
// this could be initialized from categoryDefinitions but dunno how at the moment
2012-09-18 15:30:32 +02:00
'category' => array (
2015-10-16 23:49:04 +02:00
'rule' => array ( 'validCategory' ),
2012-09-18 15:30:32 +02:00
'message' => 'Options : Payload delivery, Antivirus detection, Payload installation, Files dropped ...'
2012-03-23 20:04:22 +01:00
),
2012-03-15 15:06:45 +01:00
'value' => array (
2015-10-09 15:59:25 +02:00
'valueNotEmpty' => array (
'rule' => array ( 'valueNotEmpty' ),
2012-03-15 15:06:45 +01:00
),
'userdefined' => array (
2012-03-26 19:56:44 +02:00
'rule' => array ( 'validateAttributeValue' ),
2016-05-20 16:46:06 +02:00
'message' => 'Value not in the right type/format. Please double check the value or select type "other".' ,
2012-03-15 15:06:45 +01:00
//'allowEmpty' => false,
//'required' => true,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
2015-08-25 10:32:26 +02:00
'uniqueValue' => array (
2012-09-18 15:30:32 +02:00
'rule' => array ( 'valueIsUnique' ),
'message' => 'A similar attribute already exists for this event.' ,
//'allowEmpty' => false,
//'required' => true,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
2012-04-10 15:47:42 +02:00
),
2012-03-15 15:06:45 +01:00
),
'to_ids' => array (
'boolean' => array (
'rule' => array ( 'boolean' ),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
'required' => false ,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
'uuid' => array (
'uuid' => array (
'rule' => array ( 'uuid' ),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
2015-08-17 16:10:10 +02:00
'unique' => array (
'rule' => 'isUnique' ,
'message' => 'The UUID provided is not unique' ,
'required' => 'create'
)
2012-03-15 15:06:45 +01:00
),
2013-06-10 17:33:03 +02:00
'distribution' => array (
2015-04-18 07:53:18 +02:00
'rule' => array ( 'inList' , array ( '0' , '1' , '2' , '3' , '4' , '5' )),
2016-05-20 05:11:11 +02:00
'message' => 'Options: Your organisation only, This community only, Connected communities, All communities, Sharing group, Inherit event' ,
2013-06-10 17:33:03 +02:00
//'allowEmpty' => false,
'required' => true ,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
2013-07-16 15:28:04 +02:00
),
2012-03-15 15:06:45 +01:00
);
2016-06-04 01:08:16 +02:00
2014-06-12 13:59:54 +02:00
// automatic resolution of complex types
2016-06-04 01:10:45 +02:00
// If the complex type "file" is chosen for example, then the system will try to categorise the values entered into a complex template field based
2014-06-12 13:59:54 +02:00
// on the regular expression rules
public $validTypeGroups = array (
'File' => array (
'description' => '' ,
'types' => array ( 'filename' , 'filename|md5' , 'filename|sha1' , 'filename|sha256' , 'md5' , 'sha1' , 'sha256' ),
),
'CnC' => array (
'description' => '' ,
'types' => array ( 'url' , 'domain' , 'hostname' , 'ip-dst' ),
),
);
2016-06-04 01:08:16 +02:00
2014-06-12 13:59:54 +02:00
public $typeGroupCategoryMapping = array (
'Payload delviery' => array ( 'File' , 'CnC' ),
'Payload installation' => array ( 'File' ),
'Artifacts dropped' => array ( 'File' ),
'Network activity' => array ( 'CnC' ),
);
2012-03-15 15:06:45 +01:00
2012-10-17 14:45:26 +02:00
public function __construct ( $id = false , $table = null , $ds = null ) {
parent :: __construct ( $id , $table , $ds );
2015-07-06 18:19:51 +02:00
}
2012-10-17 14:45:26 +02:00
2012-03-15 15:06:45 +01:00
public $belongsTo = array (
'Event' => array (
'className' => 'Event' ,
'foreignKey' => 'event_id' ,
'conditions' => '' ,
'fields' => '' ,
2012-11-14 16:14:04 +01:00
'order' => '' ,
2016-05-06 23:34:26 +02:00
'counterCache' => 'attribute_count' ,
2016-07-11 20:22:42 +02:00
'counterScope' => array ( 'Attribute.deleted' => 0 )
2015-04-13 12:42:26 +02:00
),
'SharingGroup' => array (
'className' => 'SharingGroup' ,
'foreignKey' => 'sharing_group_id'
2012-03-15 15:06:45 +01:00
)
);
2016-06-04 01:08:16 +02:00
2015-08-07 12:04:44 +02:00
public $hashTypes = array (
'md5' => array (
'length' => 32 ,
'pattern' => '#^[0-9a-f]{32}$#' ,
'lowerCase' => true ,
),
'sha1' => array (
'length' => 40 ,
'pattern' => '#^[0-9a-f]{40}$#' ,
'lowerCase' => true ,
),
'sha256' => array (
'length' => 64 ,
'pattern' => '#^[0-9a-f]{64}$#' ,
'lowerCase' => true ,
)
);
2012-03-25 15:56:29 +02:00
2012-11-23 08:57:34 +01:00
public function beforeSave ( $options = array ()) {
2012-09-18 15:30:32 +02:00
// explode value of composite type in value1 and value2
// or copy value to value1 if not composite type
if ( ! empty ( $this -> data [ 'Attribute' ][ 'type' ])) {
2012-09-19 11:05:10 +02:00
$compositeTypes = $this -> getCompositeTypes ();
2012-09-18 15:30:32 +02:00
// explode composite types in value1 and value2
2013-03-08 13:16:02 +01:00
$pieces = explode ( '|' , $this -> data [ 'Attribute' ][ 'value' ]);
if ( in_array ( $this -> data [ 'Attribute' ][ 'type' ], $compositeTypes )) {
if ( 2 != count ( $pieces )) {
throw new InternalErrorException ( 'Composite type, but value not explodable' );
2012-09-18 15:30:32 +02:00
}
2013-03-08 13:16:02 +01:00
$this -> data [ 'Attribute' ][ 'value1' ] = $pieces [ 0 ];
$this -> data [ 'Attribute' ][ 'value2' ] = $pieces [ 1 ];
} else {
$total = implode ( '|' , $pieces );
$this -> data [ 'Attribute' ][ 'value1' ] = $total ;
$this -> data [ 'Attribute' ][ 'value2' ] = '' ;
}
2012-09-18 15:30:32 +02:00
}
2016-06-04 01:08:16 +02:00
2015-04-18 07:53:18 +02:00
if ( $this -> data [ 'Attribute' ][ 'distribution' ] != 4 ) $this -> data [ 'Attribute' ][ 'sharing_group_id' ] = 0 ;
2016-06-04 01:08:16 +02:00
2013-04-22 10:59:55 +02:00
// update correlation... (only needed here if there's an update)
2015-09-07 10:06:34 +02:00
if ( $this -> id || ! empty ( $this -> data [ 'Attribute' ][ 'id' ])) {
2016-06-04 01:14:25 +02:00
$this -> __beforeSaveCorrelation ( $this -> data [ 'Attribute' ]);
2015-09-07 10:06:34 +02:00
}
2012-09-18 15:30:32 +02:00
// always return true after a beforeSave()
return true ;
2012-03-20 13:40:58 +01:00
}
2012-03-25 15:56:29 +02:00
2013-11-06 10:35:51 +01:00
public function afterSave ( $created , $options = array ()) {
2013-04-22 10:59:55 +02:00
// update correlation...
2016-05-06 23:34:26 +02:00
if ( isset ( $this -> data [ 'Attribute' ][ 'deleted' ]) && $this -> data [ 'Attribute' ][ 'deleted' ]) {
$this -> __beforeSaveCorrelation ( $this -> data [ 'Attribute' ]);
} else {
$this -> __afterSaveCorrelation ( $this -> data [ 'Attribute' ]);
}
2012-09-18 15:30:32 +02:00
$result = true ;
// if the 'data' field is set on the $this->data then save the data to the correct file
if ( isset ( $this -> data [ 'Attribute' ][ 'type' ]) && $this -> typeIsAttachment ( $this -> data [ 'Attribute' ][ 'type' ]) && ! empty ( $this -> data [ 'Attribute' ][ 'data' ])) {
2013-04-16 16:59:12 +02:00
$result = $result && $this -> saveBase64EncodedAttachment ( $this -> data [ 'Attribute' ]); // TODO : is this correct?
2012-09-18 15:30:32 +02:00
}
return $result ;
2012-05-22 13:58:37 +02:00
}
2012-11-23 08:57:34 +01:00
public function beforeDelete ( $cascade = true ) {
2012-09-18 15:30:32 +02:00
// delete attachments from the disk
2013-02-04 17:55:35 +01:00
$this -> read (); // first read the attribute from the db
2012-09-18 15:30:32 +02:00
if ( $this -> typeIsAttachment ( $this -> data [ 'Attribute' ][ 'type' ])) {
// only delete the file if it exists
$filepath = APP . " files " . DS . $this -> data [ 'Attribute' ][ 'event_id' ] . DS . $this -> data [ 'Attribute' ][ 'id' ];
2016-05-20 16:57:34 +02:00
$file = new File ( $filepath );
2012-09-18 15:30:32 +02:00
if ( $file -> exists ()) {
if ( ! $file -> delete ()) {
throw new InternalErrorException ( 'Delete of file attachment failed. Please report to administrator.' );
}
}
}
2013-04-16 16:59:12 +02:00
// update correlation..
$this -> __beforeDeleteCorrelation ( $this -> data [ 'Attribute' ][ 'id' ]);
2012-03-23 20:04:22 +01:00
}
2012-03-25 15:56:29 +02:00
2012-11-23 08:57:34 +01:00
public function beforeValidate ( $options = array ()) {
2012-11-26 15:34:54 +01:00
parent :: beforeValidate ();
2012-09-18 15:30:32 +02:00
if ( ! isset ( $this -> data [ 'Attribute' ][ 'type' ])) {
return false ;
}
2016-05-27 16:00:55 +02:00
// remove leading and trailing blanks
$this -> data [ 'Attribute' ][ 'value' ] = trim ( $this -> data [ 'Attribute' ][ 'value' ]);
2015-07-06 18:19:51 +02:00
// make some last changes to the inserted value
$this -> data [ 'Attribute' ][ 'value' ] = $this -> modifyBeforeValidation ( $this -> data [ 'Attribute' ][ 'type' ], $this -> data [ 'Attribute' ][ 'value' ]);
2015-11-09 12:36:49 +01:00
2013-07-13 08:37:41 +02:00
// set to_ids if it doesn't exist
if ( empty ( $this -> data [ 'Attribute' ][ 'to_ids' ])) {
2016-09-05 00:45:51 +02:00
$this -> data [ 'Attribute' ][ 'to_ids' ] = 0 ;
2013-07-13 08:37:41 +02:00
}
2012-09-18 15:30:32 +02:00
// generate UUID if it doesn't exist
if ( empty ( $this -> data [ 'Attribute' ][ 'uuid' ])) {
2016-07-11 00:59:47 +02:00
$this -> data [ 'Attribute' ][ 'uuid' ] = CakeText :: uuid ();
2012-09-18 15:30:32 +02:00
}
2013-06-07 10:24:03 +02:00
// generate timestamp if it doesn't exist
if ( empty ( $this -> data [ 'Attribute' ][ 'timestamp' ])) {
$date = new DateTime ();
$this -> data [ 'Attribute' ][ 'timestamp' ] = $date -> getTimestamp ();
}
2016-05-20 04:59:33 +02:00
// TODO: add explanatory comment
2013-07-08 17:15:04 +02:00
$result = $this -> runRegexp ( $this -> data [ 'Attribute' ][ 'type' ], $this -> data [ 'Attribute' ][ 'value' ]);
if ( ! $result ) {
$this -> invalidate ( 'value' , 'This value is blocked by a regular expression in the import filters.' );
} else {
$this -> data [ 'Attribute' ][ 'value' ] = $result ;
}
2016-05-20 04:59:33 +02:00
// TODO: add explanatory comment
2016-01-07 16:33:35 +01:00
if ( ! isset ( $this -> data [ 'Attribute' ][ 'distribution' ]) || $this -> data [ 'Attribute' ][ 'distribution' ] != 4 ) $this -> data [ 'Attribute' ][ 'sharing_group_id' ] = 0 ;
2016-03-07 02:40:36 +01:00
if ( ! isset ( $this -> data [ 'Attribute' ][ 'distribution' ])) $this -> data [ 'Attribute' ][ 'distribution' ] = 5 ;
2016-05-20 04:59:33 +02:00
// return true, otherwise the object cannot be saved
2012-09-18 15:30:32 +02:00
return true ;
2012-03-25 15:56:29 +02:00
}
2015-10-16 23:49:04 +02:00
public function validCategory ( $fields ) {
$validCategories = array_keys ( $this -> categoryDefinitions );
if ( in_array ( $fields [ 'category' ], $validCategories )) return true ;
return false ;
}
2016-06-04 01:08:16 +02:00
2012-09-18 15:30:32 +02:00
public function valueIsUnique ( $fields ) {
2016-06-03 01:27:12 +02:00
if ( isset ( $this -> data [ 'Attribute' ][ 'deleted' ]) && $this -> data [ 'Attribute' ][ 'deleted' ]) return true ;
2012-09-18 15:30:32 +02:00
$value = $fields [ 'value' ];
2012-09-19 11:05:10 +02:00
$eventId = $this -> data [ 'Attribute' ][ 'event_id' ];
2012-09-18 15:30:32 +02:00
$type = $this -> data [ 'Attribute' ][ 'type' ];
$category = $this -> data [ 'Attribute' ][ 'category' ];
// check if the attribute already exists in the same event
2012-09-19 11:05:10 +02:00
$conditions = array ( 'Attribute.event_id' => $eventId ,
2012-09-18 15:30:32 +02:00
'Attribute.type' => $type ,
'Attribute.category' => $category ,
2016-05-06 23:34:26 +02:00
'Attribute.value' => $value ,
2016-07-11 20:22:42 +02:00
'Attribute.deleted' => 0
2012-09-18 15:30:32 +02:00
);
if ( isset ( $this -> data [ 'Attribute' ][ 'id' ])) {
$conditions [ 'Attribute.id !=' ] = $this -> data [ 'Attribute' ][ 'id' ];
}
2015-08-25 10:32:26 +02:00
$params = array ( 'recursive' => - 1 ,
2012-09-18 15:30:32 +02:00
'conditions' => $conditions ,
);
if ( 0 != $this -> find ( 'count' , $params )) {
2016-05-20 04:59:33 +02:00
// value isn't unique
2012-09-18 15:30:32 +02:00
return false ;
}
2016-05-20 04:59:33 +02:00
// value is unique
2012-09-18 15:30:32 +02:00
return true ;
2012-04-10 15:47:42 +02:00
}
2012-09-18 15:30:32 +02:00
public function validateTypeValue ( $fields ) {
$category = $this -> data [ 'Attribute' ][ 'category' ];
2012-09-19 11:05:10 +02:00
if ( isset ( $this -> categoryDefinitions [ $category ][ 'types' ])) {
return in_array ( $fields [ 'type' ], $this -> categoryDefinitions [ $category ][ 'types' ]);
2012-09-18 15:30:32 +02:00
}
return false ;
2012-05-31 17:12:26 +02:00
}
2012-09-24 08:27:22 +02:00
public function validateAttributeValue ( $fields ) {
2012-09-18 15:30:32 +02:00
$value = $fields [ 'value' ];
2014-08-13 16:13:38 +02:00
return $this -> runValidation ( $value , $this -> data [ 'Attribute' ][ 'type' ]);
}
2016-06-04 01:08:16 +02:00
2015-07-06 18:19:51 +02:00
private $__hexHashLengths = array (
'authentihash' => 64 ,
'md5' => 32 ,
'imphash' => 32 ,
'sha1' => 40 ,
2016-02-13 16:43:41 +01:00
'x509-fingerprint-sha1' => 40 ,
2015-07-06 18:19:51 +02:00
'pehash' => 40 ,
'sha224' => 56 ,
'sha256' => 64 ,
'sha384' => 96 ,
'sha512' => 128 ,
'sha512/224' => 56 ,
'sha512/256' => 64 ,
);
2016-06-04 01:08:16 +02:00
2014-08-13 16:13:38 +02:00
public function runValidation ( $value , $type ) {
2012-09-19 11:24:12 +02:00
$returnValue = false ;
2012-09-18 15:30:32 +02:00
// check data validation
2016-06-04 15:45:39 +02:00
switch ( $type ) {
2012-09-18 15:30:32 +02:00
case 'md5' :
2015-07-06 18:19:51 +02:00
case 'imphash' :
case 'sha1' :
case 'sha224' :
case 'sha256' :
case 'sha384' :
case 'sha512' :
case 'sha512/224' :
case 'sha512/256' :
case 'authentihash' :
2016-02-13 16:43:41 +01:00
case 'x509-fingerprint-sha1' :
2015-07-06 18:19:51 +02:00
$length = $this -> __hexHashLengths [ $type ];
if ( preg_match ( " #^[0-9a-f] { " . $length . " } $ # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
} else {
2016-05-20 16:46:06 +02:00
$returnValue = 'Checksum has an invalid length or format (expected: ' . $length . ' hexadecimal characters). Please double check the value or select type "other".' ;
2012-09-18 15:30:32 +02:00
}
break ;
2015-07-06 18:19:51 +02:00
case 'tlsh' :
if ( preg_match ( " #^[0-9a-f] { 35,} $ # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
} else {
2016-05-20 16:46:06 +02:00
$returnValue = 'Checksum has an invalid length or format (expected: at least 35 hexadecimal characters). Please double check the value or select type "other".' ;
2012-09-18 15:30:32 +02:00
}
break ;
2015-07-06 18:19:51 +02:00
case 'pehash' :
if ( preg_match ( " #^[0-9a-f] { 40} $ # " , $value )) {
2013-06-12 16:50:21 +02:00
$returnValue = true ;
} else {
2015-07-06 18:19:51 +02:00
$returnValue = 'The input doesn\'t match the expected sha1 format (expected: 40 hexadecimal characters). Keep in mind that MISP currently only supports SHA1 for PEhashes, if you would like to get the support extended to other hash types, make sure to create a github ticket about it at https://github.com/MISP/MISP!' ;
2013-06-12 16:50:21 +02:00
}
break ;
2015-07-06 18:19:51 +02:00
case 'ssdeep' :
if ( substr_count ( $value , ':' ) == 2 ) {
$parts = explode ( ':' , $value );
if ( is_numeric ( $parts [ 0 ])) $returnValue = true ;
2016-06-04 01:10:45 +02:00
}
2015-07-06 18:19:51 +02:00
if ( ! $returnValue ) $returnValue = 'Invalid SSDeep hash. The format has to be blocksize:hash:hash' ;
break ;
2013-08-13 13:19:27 +02:00
case 'http-method' :
if ( preg_match ( " #(OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT|PROPFIND|PROPPATCH|MKCOL|COPY|MOVE|LOCK|UNLOCK|VERSION-CONTROL|REPORT|CHECKOUT|CHECKIN|UNCHECKOUT|MKWORKSPACE|UPDATE|LABEL|MERGE|BASELINE-CONTROL|MKACTIVITY|ORDERPATCH|ACL|PATCH|SEARCH)# " , $value )) {
2016-09-05 00:45:51 +02:00
$returnValue = true ;
2013-08-13 13:19:27 +02:00
} else {
$returnValue = 'Unknown HTTP method.' ;
}
break ;
2015-07-06 18:19:51 +02:00
case 'filename|pehash' :
2012-09-18 15:30:32 +02:00
// no newline
2015-07-06 18:19:51 +02:00
if ( preg_match ( " #^.+ \ |[0-9a-f] { 40} $ # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2015-07-06 18:19:51 +02:00
} else {
$returnValue = 'The input doesn\'t match the expected filename|sha1 format (expected: filename|40 hexadecimal characters). Keep in mind that MISP currently only supports SHA1 for PEhashes, if you would like to get the support extended to other hash types, make sure to create a github ticket about it at https://github.com/MISP/MISP!' ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'filename|md5' :
2016-06-04 01:10:45 +02:00
case 'filename|sha1' :
2015-07-06 18:19:51 +02:00
case 'filename|imphash' :
case 'filename|sha224' :
case 'filename|sha256' :
case 'filename|sha384' :
case 'filename|sha512' :
case 'filename|sha512/224' :
case 'filename|sha512/256' :
case 'filename|authentihash' :
$parts = explode ( '|' , $type );
$length = $this -> __hexHashLengths [ $parts [ 1 ]];
if ( preg_match ( " #^.+ \ |[0-9a-f] { " . $length . " } $ # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
} else {
2016-05-20 16:46:06 +02:00
$returnValue = 'Checksum has an invalid length or format (expected: filename|' . $length . ' hexadecimal characters). Please double check the value or select type "other".' ;
2012-09-18 15:30:32 +02:00
}
break ;
2015-07-06 18:19:51 +02:00
case 'filename|ssdeep' :
2016-05-20 04:59:33 +02:00
if ( substr_count ( $value , '|' ) != 1 || ! preg_match ( " #^.+ \ |.+ $ # " , $value )) {
$returnValue = 'Invalid composite type. The format has to be ' . $type . '.' ;
} else {
2015-07-06 18:19:51 +02:00
$composite = explode ( '|' , $value );
$value = $composite [ 1 ];
if ( substr_count ( $value , ':' ) == 2 ) {
$parts = explode ( ':' , $value );
if ( is_numeric ( $parts [ 0 ])) $returnValue = true ;
}
if ( ! $returnValue ) $returnValue = 'Invalid SSDeep hash (expected: blocksize:hash:hash).' ;
2013-06-12 16:50:21 +02:00
}
break ;
2015-07-06 18:19:51 +02:00
case 'filename|tlsh' :
if ( preg_match ( " #^.+ \ |[0-9a-f] { 35,} $ # " , $value )) {
2013-06-12 16:50:21 +02:00
$returnValue = true ;
} else {
2016-05-20 16:46:06 +02:00
$returnValue = 'Checksum has an invalid length or format (expected: filename|at least 35 hexadecimal characters). Please double check the value or select type "other".' ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'ip-src' :
case 'ip-dst' :
$parts = explode ( " / " , $value );
2016-05-20 16:46:06 +02:00
// [0] = the IP
2012-09-18 15:30:32 +02:00
// [1] = the network address
if ( count ( $parts ) <= 2 ) {
2016-05-20 16:46:06 +02:00
// IPv4 and IPv6 matching
2016-05-20 04:59:33 +02:00
if ( filter_var ( $parts [ 0 ], FILTER_VALIDATE_IP )) {
2016-05-20 16:46:06 +02:00
// IP is validated, now check if we have a valid network mask
2012-09-18 15:30:32 +02:00
if ( empty ( $parts [ 1 ])) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
} else {
if ( is_numeric ( $parts [ 1 ]) && $parts [ 1 ] < 129 ) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
}
}
}
}
2012-09-19 11:24:12 +02:00
if ( ! $returnValue ) {
2016-05-20 16:46:06 +02:00
$returnValue = 'IP address has an invalid format. Please double check the value or select type "other".' ;
2012-09-19 11:24:12 +02:00
}
2012-09-18 15:30:32 +02:00
break ;
case 'hostname' :
case 'domain' :
2015-06-18 14:49:25 +02:00
if ( preg_match ( " #^[A-Z0-9. \ -_]+ \ .[A-Z] { 2,} $ #i " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
} else {
2016-05-20 16:46:06 +02:00
$returnValue = 'Domain name has an invalid format. Please double check the value or select type "other".' ;
2012-09-18 15:30:32 +02:00
}
break ;
2015-11-24 10:40:43 +01:00
case 'domain|ip' :
if ( preg_match ( " #^[A-Z0-9. \ -_]+ \ .[A-Z] { 2,} \ |.* $ #i " , $value )) {
$parts = explode ( '|' , $value );
2016-05-20 04:59:33 +02:00
if ( filter_var ( $parts [ 1 ], FILTER_VALIDATE_IP )) {
$returnValue = true ;
} else {
2016-05-20 16:46:06 +02:00
$returnValue = 'IP address has an invalid format.' ;
2016-05-20 04:59:33 +02:00
}
2015-11-24 10:40:43 +01:00
} else {
2016-05-20 16:46:06 +02:00
$returnValue = 'Domain name has an invalid format.' ;
2015-11-24 10:40:43 +01:00
}
2016-06-04 01:10:45 +02:00
break ;
2012-09-18 15:30:32 +02:00
case 'email-src' :
case 'email-dst' :
2015-07-06 18:19:51 +02:00
case 'target-email' :
case 'whois-registrant-email' :
2012-09-18 15:30:32 +02:00
// we don't use the native function to prevent issues with partial email addresses
2016-07-10 01:32:37 +02:00
if ( preg_match ( " #^[A-Z0-9._&%+-=~]*@[A-Z0-9. \ -_]+ \ .[A-Z] { 2,} $ #i " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
} else {
2016-05-20 16:46:06 +02:00
$returnValue = 'Email address has an invalid format. Please double check the value or select type "other".' ;
2012-09-18 15:30:32 +02:00
}
break ;
2013-03-18 16:50:28 +01:00
case 'vulnerability' :
2014-01-14 10:38:16 +01:00
if ( preg_match ( " #^(CVE-)[0-9] { 4}(-)[0-9] { 4,6} $ # " , $value )) {
2013-03-18 16:50:28 +01:00
$returnValue = true ;
} else {
$returnValue = 'Invalid format. Expected: CVE-xxxx-xxxx.' ;
}
break ;
2013-06-03 09:38:55 +02:00
case 'named pipe' :
2014-03-06 17:21:57 +01:00
if ( ! preg_match ( " # \n # " , $value )) {
2013-06-03 09:38:55 +02:00
$returnValue = true ;
}
break ;
2015-07-06 18:19:51 +02:00
case 'windows-service-name' :
case 'windows-service-displayname' :
2016-05-20 04:59:33 +02:00
if ( strlen ( $value ) > 256 || preg_match ( '#[\\\/]#' , $value )) {
$returnValue = 'Invalid format. Only values shorter than 256 characters that don\'t include any forward or backward slashes are allowed.' ;
} else {
$returnValue = true ;
}
2015-07-06 18:19:51 +02:00
break ;
2013-06-03 09:38:55 +02:00
case 'mutex' :
2013-02-11 17:23:07 +01:00
case 'AS' :
case 'snort' :
case 'pattern-in-file' :
case 'pattern-in-traffic' :
case 'pattern-in-memory' :
case 'yara' :
2013-02-11 15:56:10 +01:00
case 'attachment' :
case 'malware-sample' :
2013-02-11 17:23:07 +01:00
$returnValue = true ;
break ;
case 'link' :
if ( preg_match ( '#^(http|ftp)(s)?\:\/\/((([a-z|0-9|\-]{1,25})(\.)?){2,7})($|/.*$)#i' , $value ) && ! preg_match ( " # \n # " , $value )) {
$returnValue = true ;
}
break ;
case 'comment' :
case 'text' :
2012-09-18 15:30:32 +02:00
case 'other' :
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
break ;
2016-06-04 01:14:25 +02:00
case 'target-user' :
2015-07-06 18:19:51 +02:00
case 'campaign-name' :
case 'campaign-id' :
case 'threat-actor' :
2016-06-04 01:14:25 +02:00
case 'target-machine' :
case 'target-org' :
case 'target-location' :
case 'target-external' :
case 'email-subject' :
case 'email-attachment' :
2016-01-13 13:49:57 +01:00
case 'malware-type' :
2016-06-04 01:14:25 +02:00
case 'url' :
case 'uri' :
case 'user-agent' :
case 'regkey' :
case 'regkey|value' :
2015-07-06 18:19:51 +02:00
case 'filename' :
2016-01-18 13:24:18 +01:00
case 'pdb' :
2016-08-22 03:40:17 +02:00
case 'windows-scheduled-task' :
case 'whois-registrant-name' :
2016-02-26 21:16:46 +01:00
case 'whois-registrar' :
2015-12-29 18:46:23 +01:00
case 'whois-creation-date' :
2016-06-04 01:14:25 +02:00
// no newline
if ( ! preg_match ( " # \n # " , $value )) {
$returnValue = true ;
}
break ;
case 'targeted-threat-index' :
if ( ! is_numeric ( $value ) || $value < 0 || $value > 10 ) {
2016-05-20 04:59:33 +02:00
$returnValue = 'The value has to be a number between 0 and 10.' ;
} else {
$returnValue = true ;
}
2016-06-04 01:14:25 +02:00
break ;
2015-11-09 12:36:49 +01:00
case 'iban' :
case 'bic' :
case 'btc' :
if ( preg_match ( '/^[a-zA-Z0-9]+$/' , $value )) {
$returnValue = true ;
}
break ;
2015-11-09 13:42:22 +01:00
case 'bin' :
2015-11-09 12:36:49 +01:00
case 'cc-number' :
case 'bank-account-nr' :
case 'aba-rtn' :
case 'prtn' :
case 'whois-registrant-phone' :
if ( is_numeric ( $value )) {
$returnValue = true ;
}
break ;
2012-09-18 15:30:32 +02:00
}
2012-09-19 11:24:12 +02:00
return $returnValue ;
2012-03-15 15:06:45 +01:00
}
2016-06-04 01:08:16 +02:00
2015-07-06 18:19:51 +02:00
// do some last second modifications before the validation
public function modifyBeforeValidation ( $type , $value ) {
2016-06-04 15:45:39 +02:00
switch ( $type ) {
2015-07-06 18:19:51 +02:00
case 'md5' :
case 'sha1' :
case 'sha224' :
case 'sha256' :
case 'sha384' :
case 'sha512' :
case 'sha512/224' :
case 'sha512/256' :
case 'domain' :
case 'hostname' :
case 'pehash' :
case 'authentihash' :
case 'imphash' :
case 'tlsh' :
case 'email-src' :
case 'email-dst' :
2016-06-27 14:08:54 +02:00
case 'target-email' :
case 'whois-registrant-email' :
$value = strtolower ( $value );
break ;
2016-01-01 14:17:50 +01:00
case 'domain|ip' :
2016-06-14 02:20:31 +02:00
$parts = explode ( '|' , $value );
if ( filter_var ( $parts [ 1 ], FILTER_VALIDATE_IP , FILTER_FLAG_IPV6 )) {
// convert IPv6 address to compressed format
$parts [ 1 ] = inet_ntop ( inet_pton ( $value ));
$value = implode ( '|' , $parts );
}
2015-07-06 18:19:51 +02:00
break ;
case 'filename|md5' :
2016-06-04 01:10:45 +02:00
case 'filename|sha1' :
2015-07-06 18:19:51 +02:00
case 'filename|imphash' :
case 'filename|sha224' :
case 'filename|sha256' :
case 'filename|sha384' :
case 'filename|sha512' :
case 'filename|sha512/224' :
case 'filename|sha512/256' :
case 'filename|authentihash' :
case 'filename|pehash' :
case 'filename|tlsh' :
$pieces = explode ( '|' , $value );
$value = $pieces [ 0 ] . '|' . strtolower ( $pieces [ 1 ]);
break ;
case 'http-method' :
$value = strtoupper ( $value );
break ;
case 'cc-number' :
case 'bin' :
$value = preg_replace ( '/[^0-9]+/' , '' , $value );
break ;
case 'iban' :
2015-11-09 12:36:49 +01:00
case 'bic' :
2015-07-06 18:19:51 +02:00
$value = strtoupper ( $value );
$value = preg_replace ( '/[^0-9A-Z]+/' , '' , $value );
break ;
case 'prtn' :
case 'whois-registrant-phone' :
2016-01-14 19:46:35 +01:00
if ( substr ( $value , 0 , 1 ) == '+' ) $value = '00' . substr ( $value , 1 );
2015-07-06 18:19:51 +02:00
$value = preg_replace ( '/[^0-9]+/' , '' , $value );
break ;
2015-12-09 02:00:23 +01:00
case 'url' :
$value = preg_replace ( '/^hxxp/i' , 'http' , $value );
$value = preg_replace ( '/\[\.\]/' , '.' , $value );
break ;
2016-02-13 16:43:41 +01:00
case 'x509-fingerprint-sha1' :
$value = str_replace ( ':' , '' , $value );
$value = strtolower ( $value );
break ;
2016-06-14 02:20:31 +02:00
case 'ip-src' :
case 'ip-dst' :
if ( filter_var ( $value , FILTER_VALIDATE_IP , FILTER_FLAG_IPV6 )) {
// convert IPv6 address to compressed format
$value = inet_ntop ( inet_pton ( $value ));
}
break ;
2015-07-06 18:19:51 +02:00
}
return $value ;
}
2012-03-25 15:56:29 +02:00
2012-09-18 15:30:32 +02:00
public function getCompositeTypes () {
// build the list of composite Attribute.type dynamically by checking if type contains a |
// default composite types
2012-09-19 11:05:10 +02:00
$compositeTypes = array ( 'malware-sample' ); // TODO hardcoded composite
2012-09-18 15:30:32 +02:00
// dynamically generated list
2012-09-19 11:05:10 +02:00
foreach ( array_keys ( $this -> typeDefinitions ) as $type ) {
2012-09-18 15:30:32 +02:00
$pieces = explode ( '|' , $type );
if ( 2 == count ( $pieces )) {
2012-09-19 11:05:10 +02:00
$compositeTypes [] = $type ;
2012-09-18 15:30:32 +02:00
}
}
2012-09-19 11:05:10 +02:00
return $compositeTypes ;
2012-09-18 15:30:32 +02:00
}
2012-03-25 15:56:29 +02:00
2016-05-20 04:59:33 +02:00
public function isOwnedByOrg ( $attributeId , $org ) {
$this -> id = $attributeId ;
2012-09-18 15:30:32 +02:00
$this -> read ();
2015-04-14 17:51:38 +02:00
return $this -> data [ 'Event' ][ 'org_id' ] === $org ;
2012-03-20 14:57:52 +01:00
}
2012-03-25 15:56:29 +02:00
2012-09-18 15:30:32 +02:00
public function getRelatedAttributes ( $attribute , $fields = array ()) {
// LATER getRelatedAttributes($attribute) this might become a performance bottleneck
2016-05-20 04:59:33 +02:00
// exclude these specific categories from being linked
2012-09-18 15:30:32 +02:00
switch ( $attribute [ 'category' ]) {
case 'Antivirus detection' :
return null ;
}
2016-05-20 04:59:33 +02:00
// exclude these specific types from being linked
2012-09-18 15:30:32 +02:00
switch ( $attribute [ 'type' ]) {
case 'other' :
case 'comment' :
return null ;
}
// prepare the conditions
$conditions = array (
'Attribute.event_id !=' => $attribute [ 'event_id' ],
);
2016-05-20 04:59:33 +02:00
// prevent issues with empty fields
if ( empty ( $attribute [ 'value1' ])) {
2012-09-18 15:30:32 +02:00
return null ;
}
if ( empty ( $attribute [ 'value2' ])) {
// no value2, only search for value 1
$conditions [ 'OR' ] = array (
'Attribute.value1' => $attribute [ 'value1' ],
'Attribute.value2' => $attribute [ 'value1' ],
);
} else {
// value2 also set, so search for both
2012-12-05 14:52:03 +01:00
$conditions [ 'AND' ] = array ( // TODO was OR
2012-09-18 15:30:32 +02:00
'Attribute.value1' => array ( $attribute [ 'value1' ], $attribute [ 'value2' ]),
'Attribute.value2' => array ( $attribute [ 'value1' ], $attribute [ 'value2' ]),
);
}
// do the search
if ( empty ( $fields )) {
$fields = array ( 'Attribute.*' );
}
2012-09-19 11:05:10 +02:00
$similarEvents = $this -> find ( 'all' , array ( 'conditions' => $conditions ,
2012-09-18 15:30:32 +02:00
'fields' => $fields ,
'recursive' => 0 ,
'group' => array ( 'Attribute.event_id' ),
'order' => 'Attribute.event_id DESC' , )
);
2012-09-19 11:05:10 +02:00
return $similarEvents ;
2012-03-15 15:06:45 +01:00
}
2012-03-25 15:56:29 +02:00
2012-09-18 15:30:32 +02:00
public function typeIsMalware ( $type ) {
2012-09-19 11:05:10 +02:00
if ( in_array ( $type , $this -> zippedDefinitions )) {
2012-09-18 15:30:32 +02:00
return true ;
} else {
return false ;
}
2012-07-10 11:39:43 +02:00
}
2012-09-20 11:34:41 +02:00
2012-09-18 15:30:32 +02:00
public function typeIsAttachment ( $type ) {
2012-09-19 11:05:10 +02:00
if (( in_array ( $type , $this -> zippedDefinitions )) || ( in_array ( $type , $this -> uploadDefinitions ))) {
2012-09-18 15:30:32 +02:00
return true ;
} else {
return false ;
}
2012-05-21 15:20:25 +02:00
}
2012-09-20 11:34:41 +02:00
2012-09-18 15:30:32 +02:00
public function base64EncodeAttachment ( $attribute ) {
$filepath = APP . " files " . DS . $attribute [ 'event_id' ] . DS . $attribute [ 'id' ];
$file = new File ( $filepath );
2016-05-20 16:57:34 +02:00
if ( ! $file -> readable ()) {
2012-09-18 15:30:32 +02:00
return '' ;
}
$content = $file -> read ();
return base64_encode ( $content );
2012-05-21 15:20:25 +02:00
}
2012-09-18 15:30:32 +02:00
public function saveBase64EncodedAttachment ( $attribute ) {
2012-09-19 11:05:10 +02:00
$rootDir = APP . DS . " files " . DS . $attribute [ 'event_id' ];
$dir = new Folder ( $rootDir , true ); // create directory structure
$destpath = $rootDir . DS . $attribute [ 'id' ];
2016-05-31 18:00:15 +02:00
$file = new File ( $destpath , true ); // create the file
2012-09-19 11:05:10 +02:00
$decodedData = base64_decode ( $attribute [ 'data' ]); // decode
if ( $file -> write ( $decodedData )) { // save the data
2012-09-18 15:30:32 +02:00
return true ;
} else {
// error
return false ;
}
2012-05-22 13:58:37 +02:00
}
2014-01-13 12:47:43 +01:00
public function uploadAttachment ( $fileP , $realFileName , $malware , $eventId = null , $category = null , $extraPath = '' , $fullFileName = '' , $dist , $fromGFI = false ) {
2012-09-24 16:02:01 +02:00
// Check if there were problems with the file upload
// only keep the last part of the filename, this should prevent directory attacks
$filename = basename ( $fileP );
$tmpfile = new File ( $fileP );
// save the file-info in the database
$this -> create ();
$this -> data [ 'Attribute' ][ 'event_id' ] = $eventId ;
2014-01-13 12:47:43 +01:00
$this -> data [ 'Attribute' ][ 'distribution' ] = $dist ;
2012-09-24 16:02:01 +02:00
if ( $malware ) {
2012-11-14 17:16:36 +01:00
$md5 = ! $tmpfile -> size () ? md5_file ( $fileP ) : $tmpfile -> md5 ();
2012-10-17 10:42:09 +02:00
$this -> data [ 'Attribute' ][ 'category' ] = $category ? $category : " Payload delivery " ;
2012-09-24 16:02:01 +02:00
$this -> data [ 'Attribute' ][ 'type' ] = " malware-sample " ;
2012-11-14 16:14:04 +01:00
$this -> data [ 'Attribute' ][ 'value' ] = $fullFileName ? $fullFileName . '|' . $md5 : $filename . '|' . $md5 ; // TODO gives problems with bigger files
2016-05-20 04:59:33 +02:00
$this -> data [ 'Attribute' ][ 'to_ids' ] = 1 ; // LATER let user choose whether to send this to an IDS
if ( $fromGFI ) $this -> data [ 'Attribute' ][ 'comment' ] = 'GFI import' ;
2012-09-24 16:02:01 +02:00
} else {
2012-10-17 10:42:09 +02:00
$this -> data [ 'Attribute' ][ 'category' ] = $category ? $category : " Artifacts dropped " ;
2012-09-24 16:02:01 +02:00
$this -> data [ 'Attribute' ][ 'type' ] = " attachment " ;
2012-10-17 10:42:09 +02:00
$this -> data [ 'Attribute' ][ 'value' ] = $fullFileName ? $fullFileName : $realFileName ;
2012-09-24 16:02:01 +02:00
$this -> data [ 'Attribute' ][ 'to_ids' ] = 0 ;
2016-05-20 04:59:33 +02:00
if ( $fromGFI ) $this -> data [ 'Attribute' ][ 'comment' ] = 'GFI import' ;
2012-09-24 16:02:01 +02:00
}
2016-05-20 04:59:33 +02:00
if ( ! $this -> save ( $this -> data )) {
// TODO: error handling
2012-09-24 16:02:01 +02:00
}
// 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
2014-01-13 12:47:43 +01:00
$rootDir = APP . " files " . DS . $eventId ;
2012-09-24 16:02:01 +02:00
$dir = new Folder ( $rootDir , true );
// move the file to the correct location
2016-06-12 05:33:34 +02:00
$destpath = $rootDir . DS . $this -> getID (); // id of the new attribute in the database
2016-05-20 04:59:33 +02:00
$file = new File ( $destpath );
2016-05-31 18:00:15 +02:00
$zipfile = new File ( $destpath . '.zip' );
2016-06-20 22:25:54 +02:00
$fileInZip = new File ( $rootDir . DS . $extraPath . $filename );
2012-09-24 16:02:01 +02:00
// zip and password protect the malware files
if ( $malware ) {
$execRetval = '' ;
$execOutput = array ();
2016-06-12 04:43:05 +02:00
exec ( 'zip -j -P infected ' . escapeshellarg ( $zipfile -> path ) . ' ' . escapeshellarg ( $fileInZip -> path ), $execOutput , $execRetval );
2013-02-04 17:55:35 +01:00
if ( $execRetval != 0 ) { // not EXIT_SUCCESS
2016-06-06 09:38:52 +02:00
throw new Exception ( 'An error has occured while attempting to zip the malware file.' );
2016-06-04 02:21:23 +02:00
}
2016-05-20 04:59:33 +02:00
$fileInZip -> delete (); // delete the original non-zipped-file
2012-09-24 16:02:01 +02:00
rename ( $zipfile -> path , $file -> path ); // rename the .zip to .nothing
} else {
$fileAttach = new File ( $fileP );
rename ( $fileAttach -> path , $file -> path );
}
2012-08-22 16:04:55 +02:00
}
2012-09-20 11:34:41 +02:00
2013-04-22 10:59:55 +02:00
public function __beforeSaveCorrelation ( $a ) {
2013-05-28 11:15:21 +02:00
// (update-only) clean up the relation of the old value: remove the existing relations related to that attribute, we DO have a reference, the id
// ==> DELETE FROM correlations WHERE 1_attribute_id = $a_id OR attribute_id = $a_id; */
2013-04-22 10:59:55 +02:00
// first check if it's an update
if ( isset ( $a [ 'id' ])) {
$this -> Correlation = ClassRegistry :: init ( 'Correlation' );
2013-05-28 11:15:21 +02:00
// FIXME : check that $a['id'] is checked correctly so that the user can't remove attributes he shouldn't
2013-04-22 10:59:55 +02:00
$dummy = $this -> Correlation -> deleteAll ( array ( 'OR' => array (
'Correlation.1_attribute_id' => $a [ 'id' ],
'Correlation.attribute_id' => $a [ 'id' ]))
);
}
}
2015-12-17 13:04:49 +01:00
public function __afterSaveCorrelation ( $a , $full = false , $event = false ) {
2015-02-16 13:30:15 +01:00
// Don't do any correlation if the type is a non correlating type
if ( ! in_array ( $a [ 'type' ], $this -> nonCorrelatingTypes )) {
2015-12-17 13:04:49 +01:00
if ( ! $event ) {
$event = $this -> Event -> find ( 'first' , array (
'recursive' => - 1 ,
'fields' => array ( 'Event.distribution' , 'Event.id' , 'Event.info' , 'Event.org_id' , 'Event.date' , 'Event.sharing_group_id' ),
2015-12-18 12:43:34 +01:00
'conditions' => array ( 'id' => $a [ 'event_id' ]),
'order' => array (),
2015-12-17 13:04:49 +01:00
));
}
2013-08-23 10:47:46 +02:00
$this -> Correlation = ClassRegistry :: init ( 'Correlation' );
2015-09-07 10:06:34 +02:00
$correlatingValues = array ( $a [ 'value1' ]);
if ( ! empty ( $a [ 'value2' ])) $correlatingValues [] = $a [ 'value2' ];
foreach ( $correlatingValues as $k => $cV ) {
$correlatingAttributes [ $k ] = $this -> find ( 'all' , array (
'conditions' => array (
'AND' => array (
2016-02-02 09:35:14 +01:00
'OR' => array (
'Attribute.value1' => $cV ,
'Attribute.value2' => $cV
),
2015-09-07 10:06:34 +02:00
'Attribute.type !=' => $this -> nonCorrelatingTypes ,
),
2016-08-28 00:06:52 +02:00
'Attribute.deleted' => 0
2015-09-07 10:06:34 +02:00
),
'recursive => -1' ,
2016-08-28 00:15:34 +02:00
'fields' => array ( 'Attribute.event_id' , 'Attribute.id' , 'Attribute.distribution' , 'Attribute.sharing_group_id' , 'Attribute.deleted' ),
2015-09-10 15:02:44 +02:00
'contain' => array ( 'Event' => array ( 'fields' => array ( 'Event.id' , 'Event.date' , 'Event.info' , 'Event.org_id' , 'Event.distribution' , 'Event.sharing_group_id' ))),
2015-12-18 12:43:34 +01:00
'order' => array (),
2015-09-07 10:06:34 +02:00
));
2016-02-02 09:35:14 +01:00
foreach ( $correlatingAttributes [ $k ] as $key => & $correlatingAttribute ) {
if ( $correlatingAttribute [ 'Attribute' ][ 'id' ] == $a [ 'id' ]) unset ( $correlatingAttributes [ $k ][ $key ]);
else if ( $correlatingAttribute [ 'Attribute' ][ 'event_id' ] == $a [ 'event_id' ]) unset ( $correlatingAttributes [ $k ][ $key ]);
else if ( $full && $correlatingAttribute [ 'Attribute' ][ 'id' ] <= $a [ 'id' ]) unset ( $correlatingAttributes [ $k ][ $key ]);
}
2015-09-07 10:06:34 +02:00
}
$correlations = array ();
foreach ( $correlatingAttributes as $k => $cA ) {
foreach ( $cA as $corr ) {
$correlations [] = array (
2016-08-28 00:03:13 +02:00
$correlatingValues [ $k ],
$event [ 'Event' ][ 'id' ],
$a [ 'id' ],
$corr [ 'Attribute' ][ 'event_id' ],
$corr [ 'Attribute' ][ 'id' ],
$corr [ 'Event' ][ 'org_id' ],
$corr [ 'Event' ][ 'distribution' ],
$corr [ 'Attribute' ][ 'distribution' ],
$corr [ 'Event' ][ 'sharing_group_id' ],
$corr [ 'Attribute' ][ 'sharing_group_id' ],
$corr [ 'Event' ][ 'date' ],
$corr [ 'Event' ][ 'info' ]
2015-09-07 10:06:34 +02:00
);
$correlations [] = array (
2016-08-28 00:03:13 +02:00
$correlatingValues [ $k ],
$corr [ 'Event' ][ 'id' ],
$corr [ 'Attribute' ][ 'id' ],
$a [ 'event_id' ],
$a [ 'id' ],
$event [ 'Event' ][ 'org_id' ],
$event [ 'Event' ][ 'distribution' ],
$a [ 'distribution' ],
$event [ 'Event' ][ 'sharing_group_id' ],
$a [ 'sharing_group_id' ],
$event [ 'Event' ][ 'date' ],
$event [ 'Event' ][ 'info' ]
2015-09-07 10:06:34 +02:00
);
}
2013-08-23 10:47:46 +02:00
}
2016-08-28 00:03:13 +02:00
$fields = array (
'value' ,
'1_event_id' ,
'1_attribute_id' ,
'event_id' ,
'attribute_id' ,
'org_id' ,
'distribution' ,
'a_distribution' ,
'sharing_group_id' ,
'a_sharing_group_id' ,
'date' ,
2016-08-28 00:45:31 +02:00
'info'
2016-08-28 00:03:13 +02:00
);
2016-08-28 00:45:31 +02:00
if ( ! empty ( $correlations )) {
$db = $this -> getDataSource ();
$db -> insertMulti ( 'correlations' , $fields , $correlations );
}
2013-05-28 11:15:21 +02:00
}
2012-08-03 12:00:16 +02:00
}
2013-04-22 10:59:55 +02:00
private function __beforeDeleteCorrelation ( $attribute_id ) {
2012-08-03 12:00:16 +02:00
$this -> Correlation = ClassRegistry :: init ( 'Correlation' );
2013-04-22 10:59:55 +02:00
// When we remove an attribute we need to
// - remove the existing relations related to that attribute, we DO have an id reference
// ==> DELETE FROM correlations WHERE 1_attribute_id = $a_id OR attribute_id = $a_id;
2012-08-03 12:00:16 +02:00
$dummy = $this -> Correlation -> deleteAll ( array ( 'OR' => array (
2013-04-22 10:59:55 +02:00
'Correlation.1_attribute_id' => $attribute_id ,
'Correlation.attribute_id' => $attribute_id ))
2012-08-03 12:00:16 +02:00
);
}
2012-11-14 16:14:04 +01:00
public function checkComposites () {
$compositeTypes = $this -> getCompositeTypes ();
$fails = array ();
2012-12-18 17:44:07 +01:00
$attributes = $this -> find ( 'all' , array ( 'recursive' => 0 ));
2012-11-14 16:14:04 +01:00
foreach ( $attributes as $attribute ) {
if (( in_array ( $attribute [ 'Attribute' ][ 'type' ], $compositeTypes )) && ( ! strlen ( $attribute [ 'Attribute' ][ 'value1' ]) || ! strlen ( $attribute [ 'Attribute' ][ 'value2' ]))) {
$fails [] = $attribute [ 'Attribute' ][ 'event_id' ] . ':' . $attribute [ 'Attribute' ][ 'id' ];
}
}
return $fails ;
}
2016-06-04 01:08:16 +02:00
2015-07-22 18:04:02 +02:00
2016-07-30 18:08:19 +02:00
public function hids ( $user , $type , $tags = '' , $from = false , $to = false , $last = false , $jobId = false ) {
2015-04-13 12:42:26 +02:00
if ( empty ( $user )) throw new MethodNotAllowedException ( 'Could not read user.' );
2013-11-15 15:39:34 +01:00
// check if it's a valid type
2015-06-10 09:50:38 +02:00
if ( $type != 'md5' && $type != 'sha1' && $type != 'sha256' ) {
2013-11-15 15:39:34 +01:00
throw new UnauthorizedException ( 'Invalid hash type.' );
}
2015-04-13 12:42:26 +02:00
$conditions = array ();
2015-06-10 09:50:38 +02:00
$typeArray = array ( $type , 'filename|' . $type );
if ( $type == 'md5' ) $typeArray [] = 'malware-sample' ;
2015-07-20 16:25:16 +02:00
$rules = array ();
2015-07-22 18:04:02 +02:00
$eventIds = $this -> Event -> fetchEventIds ( $user , $from , $to , $last );
2014-02-02 18:10:21 +01:00
if ( $tags !== '' ) {
$tag = ClassRegistry :: init ( 'Tag' );
$args = $this -> dissectArgs ( $tags );
$tagArray = $tag -> fetchEventTagIds ( $args [ 0 ], $args [ 1 ]);
2015-07-20 16:25:16 +02:00
if ( ! empty ( $tagArray [ 0 ])) {
foreach ( $eventIds as $k => $v ) {
if ( ! in_array ( $v [ 'Event' ][ 'id' ], $tagArray [ 0 ])) unset ( $eventIds [ $k ]);
}
2014-02-02 18:10:21 +01:00
}
2015-07-20 16:25:16 +02:00
if ( ! empty ( $tagArray [ 1 ])) {
foreach ( $eventIds as $k => $v ) {
if ( in_array ( $v [ 'Event' ][ 'id' ], $tagArray [ 1 ])) unset ( $eventIds [ $k ]);
}
2014-02-02 18:10:21 +01:00
}
}
2013-11-15 15:39:34 +01:00
App :: uses ( 'HidsExport' , 'Export' );
2015-07-22 18:04:02 +02:00
$continue = false ;
2016-07-30 18:08:19 +02:00
$eventCount = count ( $eventIds );
if ( $jobId ) {
$this -> Job = ClassRegistry :: init ( 'Job' );
$this -> Job -> id = $jobId ;
if ( ! $this -> Job -> exists ()) $jobId = false ;
}
foreach ( $eventIds as $k => $event ) {
2016-06-04 01:10:45 +02:00
$conditions [ 'AND' ] = array ( 'Attribute.to_ids' => 1 , 'Event.published' => 1 , 'Attribute.type' => $typeArray , 'Attribute.event_id' => $event [ 'Event' ][ 'id' ]);
2015-07-22 18:04:02 +02:00
$options = array (
'conditions' => $conditions ,
'group' => array ( 'Attribute.type' , 'Attribute.value1' ),
2015-07-20 16:25:16 +02:00
);
2015-07-22 18:04:02 +02:00
$items = $this -> fetchAttributes ( $user , $options );
if ( empty ( $items )) continue ;
2015-07-20 16:25:16 +02:00
$export = new HidsExport ();
$rules = array_merge ( $rules , $export -> export ( $items , strtoupper ( $type ), $continue ));
$continue = true ;
2016-07-30 18:08:19 +02:00
if ( $jobId && ( $k % 10 == 0 )) {
$this -> Job -> saveField ( 'progress' , $k * 80 / $eventCount );
}
2015-07-22 18:04:02 +02:00
}
2015-12-26 02:50:50 +01:00
return $rules ;
2013-11-15 15:39:34 +01:00
}
2015-07-20 16:25:16 +02:00
2016-06-04 01:08:16 +02:00
2015-07-22 18:04:02 +02:00
public function nids ( $user , $format , $id = false , $continue = false , $tags = false , $from = false , $to = false , $last = false ) {
if ( empty ( $user )) throw new MethodNotAllowedException ( 'Could not read user.' );
$eventIds = $this -> Event -> fetchEventIds ( $user , $from , $to , $last );
2016-06-04 01:08:16 +02:00
2014-02-02 18:10:21 +01:00
// If we sent any tags along, load the associated tag names for each attribute
2015-02-03 17:06:05 +01:00
if ( $tags ) {
2014-02-02 18:10:21 +01:00
$tag = ClassRegistry :: init ( 'Tag' );
$args = $this -> dissectArgs ( $tags );
$tagArray = $tag -> fetchEventTagIds ( $args [ 0 ], $args [ 1 ]);
2015-07-20 16:25:16 +02:00
if ( ! empty ( $tagArray [ 0 ])) {
foreach ( $eventIds as $k => $v ) {
if ( ! in_array ( $v [ 'Event' ][ 'id' ], $tagArray [ 0 ])) unset ( $eventIds [ $k ]);
}
2014-02-02 18:10:21 +01:00
}
2015-07-20 16:25:16 +02:00
if ( ! empty ( $tagArray [ 1 ])) {
foreach ( $eventIds as $k => $v ) {
if ( in_array ( $v [ 'Event' ][ 'id' ], $tagArray [ 1 ])) unset ( $eventIds [ $k ]);
}
2014-02-02 18:10:21 +01:00
}
}
2016-06-04 01:08:16 +02:00
2015-12-23 00:51:57 +01:00
if ( $id ) {
foreach ( $eventIds as $k => $v ) {
if ( $v [ 'Event' ][ 'id' ] !== $id ) unset ( $eventIds [ $k ]);
}
}
2015-07-20 16:25:16 +02:00
2015-07-22 18:04:02 +02:00
if ( $format == 'suricata' ) App :: uses ( 'NidsSuricataExport' , 'Export' );
else App :: uses ( 'NidsSnortExport' , 'Export' );
2016-06-04 01:08:16 +02:00
2015-07-20 16:25:16 +02:00
$rules = array ();
foreach ( $eventIds as $event ) {
$conditions [ 'AND' ] = array ( 'Attribute.to_ids' => 1 , " Event.published " => 1 , 'Attribute.event_id' => $event [ 'Event' ][ 'id' ]);
$valid_types = array ( 'ip-dst' , 'ip-src' , 'email-src' , 'email-dst' , 'email-subject' , 'email-attachment' , 'domain' , 'hostname' , 'url' , 'user-agent' , 'snort' );
$conditions [ 'AND' ][ 'Attribute.type' ] = $valid_types ;
2016-06-04 01:08:16 +02:00
2015-07-20 16:25:16 +02:00
$params = array (
2016-05-20 04:59:33 +02:00
'conditions' => $conditions , // array of conditions
'recursive' => - 1 , // int
2015-07-22 18:04:02 +02:00
'fields' => array ( 'Attribute.id' , 'Attribute.event_id' , 'Attribute.type' , 'Attribute.value' ),
'contain' => array ( 'Event' => array ( 'fields' => array ( 'Event.id' , 'Event.threat_level_id' ))),
2016-05-20 04:59:33 +02:00
'group' => array ( 'Attribute.type' , 'Attribute.value1' ), // fields to GROUP BY
2015-07-20 16:25:16 +02:00
);
2015-07-22 18:04:02 +02:00
$items = $this -> fetchAttributes ( $user , $params );
if ( empty ( $items )) continue ;
2016-05-20 04:59:33 +02:00
// export depending on the requested type
2015-07-20 16:25:16 +02:00
switch ( $format ) {
case 'suricata' :
$export = new NidsSuricataExport ();
break ;
case 'snort' :
$export = new NidsSnortExport ();
break ;
}
2015-07-22 18:04:02 +02:00
$rules = array_merge ( $rules , $export -> export ( $items , $user [ 'nids_sid' ], $format , $continue ));
2016-05-20 04:59:33 +02:00
// Only prepend the comments once
2015-07-20 16:25:16 +02:00
$continue = true ;
2013-11-18 11:35:02 +01:00
}
return $rules ;
}
2013-11-15 15:39:34 +01:00
2016-06-04 01:54:19 +02:00
public function text ( $user , $type , $tags = false , $eventId = false , $allowNonIDS = false , $from = false , $to = false , $last = false ) {
2016-06-04 01:14:25 +02:00
//restricting to non-private or same org if the user is not a site-admin.
$conditions [ 'AND' ] = array ();
if ( $allowNonIDS === false ) $conditions [ 'AND' ] = array ( 'Attribute.to_ids =' => 1 , 'Event.published =' => 1 );
if ( $type !== 'all' ) $conditions [ 'AND' ][ 'Attribute.type' ] = $type ;
if ( $from ) $conditions [ 'AND' ][ 'Event.date >=' ] = $from ;
if ( $to ) $conditions [ 'AND' ][ 'Event.date <=' ] = $to ;
2015-06-10 18:07:48 +02:00
if ( $last ) $conditions [ 'AND' ][ 'Event.publish_timestamp >=' ] = $last ;
2016-06-04 01:14:25 +02:00
if ( $eventId !== false ) {
$conditions [ 'AND' ][] = array ( 'Event.id' => $eventId );
2016-06-04 15:49:54 +02:00
} else if ( $tags !== false ) {
2016-06-04 01:14:25 +02:00
// If we sent any tags along, load the associated tag names for each attribute
$tag = ClassRegistry :: init ( 'Tag' );
$args = $this -> dissectArgs ( $tags );
$tagArray = $tag -> fetchEventTagIds ( $args [ 0 ], $args [ 1 ]);
$temp = array ();
foreach ( $tagArray [ 0 ] as $accepted ) {
$temp [ 'OR' ][] = array ( 'Event.id' => $accepted );
}
$conditions [ 'AND' ][] = $temp ;
$temp = array ();
foreach ( $tagArray [ 1 ] as $rejected ) {
$temp [ 'AND' ][] = array ( 'Event.id !=' => $rejected );
}
$conditions [ 'AND' ][] = $temp ;
}
$attributes = $this -> fetchAttributes ( $user , array (
'conditions' => $conditions ,
'order' => 'Attribute.value1 ASC' ,
'fields' => array ( 'value' ),
2015-06-10 18:07:48 +02:00
'contain' => array ( 'Event' => array (
'fields' => array ( 'Event.id' , 'Event.published' , 'Event.date' , 'Event.publish_timestamp' ),
))));
2016-06-04 01:14:25 +02:00
return $attributes ;
2016-06-04 01:54:19 +02:00
}
2016-06-04 01:08:16 +02:00
2016-06-04 01:54:19 +02:00
public function rpz ( $user , $tags = false , $eventId = false , $from = false , $to = false ) {
2016-06-04 01:14:25 +02:00
// we can group hostname and domain as well as ip-src and ip-dst in this case
$conditions [ 'AND' ] = array ( 'Attribute.to_ids' => 1 , 'Event.published' => 1 );
$typesToFetch = array ( 'ip' => array ( 'ip-src' , 'ip-dst' ), 'domain' => array ( 'domain' ), 'hostname' => array ( 'hostname' ));
if ( $from ) $conditions [ 'AND' ][ 'Event.date >=' ] = $from ;
if ( $to ) $conditions [ 'AND' ][ 'Event.date <=' ] = $to ;
if ( $eventId !== false ) {
$conditions [ 'AND' ][] = array ( 'Event.id' => $eventId );
}
if ( $tags !== false ) {
// If we sent any tags along, load the associated tag names for each attribute
$tag = ClassRegistry :: init ( 'Tag' );
$args = $this -> dissectArgs ( $tags );
$tagArray = $tag -> fetchEventTagIds ( $args [ 0 ], $args [ 1 ]);
$temp = array ();
foreach ( $tagArray [ 0 ] as $accepted ) {
$temp [ 'OR' ][] = array ( 'Event.id' => $accepted );
}
$conditions [ 'AND' ][] = $temp ;
$temp = array ();
foreach ( $tagArray [ 1 ] as $rejected ) {
$temp [ 'AND' ][] = array ( 'Event.id !=' => $rejected );
}
$conditions [ 'AND' ][] = $temp ;
}
$values = array ();
foreach ( $typesToFetch as $k => $v ) {
$temp = $this -> fetchAttributes (
$user ,
array (
'conditions' => array (
$conditions ,
array ( 'type' => $v ),
),
2016-05-20 04:59:33 +02:00
'fields' => array ( 'Attribute.value' ), // array of field names
2016-06-04 01:14:25 +02:00
)
);
if ( empty ( $temp )) continue ;
if ( $k == 'hostname' ) {
foreach ( $temp as $value ) {
$found = false ;
if ( isset ( $values [ 'domain' ])) {
foreach ( $values [ 'domain' ] as $domain ) {
if ( strpos ( $value [ 'Attribute' ][ 'value' ], $domain ) != 0 ) {
$found = true ;
}
}
}
if ( ! $found ) $values [ $k ][] = $value [ 'Attribute' ][ 'value' ];
}
2016-05-20 04:59:33 +02:00
} else {
foreach ( $temp as $value ) {
$values [ $k ][] = $value [ 'Attribute' ][ 'value' ];
}
}
unset ( $temp );
2016-06-04 01:14:25 +02:00
}
return $values ;
2016-06-04 01:54:19 +02:00
}
2016-06-04 01:08:16 +02:00
2016-09-15 17:44:59 +02:00
function bro ( $user , $type , $tags = false , $eventId = false , $from = false , $to = false , $last = false ) {
2016-08-23 14:06:06 +02:00
//restricting to non-private or same org if the user is not a site-admin.
$conditions [ 'AND' ] = array ( 'Attribute.to_ids =' => 1 , 'Event.published =' => 1 );
if ( $from ) $conditions [ 'AND' ][ 'Event.date >=' ] = $from ;
if ( $to ) $conditions [ 'AND' ][ 'Event.date <=' ] = $to ;
if ( $last ) $conditions [ 'AND' ][ 'Event.publish_timestamp >=' ] = $last ;
if ( $eventId !== false ) {
$conditions [ 'AND' ][] = array ( 'Event.id' => $eventId );
}
else if ( $tags !== false ) {
// If we sent any tags along, load the associated tag names for each attribute
$tag = ClassRegistry :: init ( 'Tag' );
$args = $this -> dissectArgs ( $tags );
$tagArray = $tag -> fetchEventTagIds ( $args [ 0 ], $args [ 1 ]);
$temp = array ();
foreach ( $tagArray [ 0 ] as $accepted ) {
$temp [ 'OR' ][] = array ( 'Event.id' => $accepted );
}
$conditions [ 'AND' ][] = $temp ;
$temp = array ();
foreach ( $tagArray [ 1 ] as $rejected ) {
$temp [ 'AND' ][] = array ( 'Event.id !=' => $rejected );
}
$conditions [ 'AND' ][] = $temp ;
}
2016-09-15 17:44:59 +02:00
App :: uses ( 'BroExport' , 'Export' );
$export = new BroExport ();
2016-09-16 14:55:25 +02:00
$this -> Whitelist = ClassRegistry :: init ( 'Whitelist' );
$this -> whitelist = $this -> Whitelist -> getBlockedValues ();
$instanceString = 'MISP' ;
if ( Configure :: read ( 'MISP.host_org_id' ) && Configure :: read ( 'MISP.host_org_id' ) > 0 ) {
$this -> Event -> Orgc -> id = Configure :: read ( 'MISP.host_org_id' );
if ( $this -> Event -> Orgc -> exists ()) {
$instanceString = $this -> Event -> Orgc -> field ( 'name' ) . ' MISP' ;
}
}
2016-09-15 17:44:59 +02:00
$mispTypes = $export -> getMispTypes ( $type );
2016-09-16 16:49:54 +02:00
$intel = array ( $export -> header );
2016-08-23 14:06:06 +02:00
foreach ( $mispTypes as $mispType ) {
2016-09-15 17:44:59 +02:00
$conditions [ 'AND' ][ 'Attribute.type' ] = $mispType [ 0 ];
2016-09-16 14:55:25 +02:00
$intel = $this -> __bro ( $intel , $user , $conditions , $mispType [ 1 ], $export , $this -> whitelist , $instanceString );
2016-08-23 14:06:06 +02:00
}
return $intel ;
}
2016-09-16 14:55:25 +02:00
private function __bro ( $intel , $user , $conditions , $valueField , $export , $whitelist , $instanceString ) {
2016-08-23 14:06:06 +02:00
$attributes = $this -> fetchAttributes ( $user , array (
'conditions' => $conditions , // array of conditions
2016-09-15 17:44:59 +02:00
'order' => 'Attribute.value' . $valueField . ' ASC' ,
2016-08-23 14:06:06 +02:00
'recursive' => - 1 , // int
2016-09-15 17:44:59 +02:00
'fields' => array ( 'Attribute.id' , 'Attribute.event_id' , 'Attribute.type' , 'Attribute.value' . $valueField . " as value " ),
2016-09-16 14:55:25 +02:00
'contain' => array ( 'Event' => array ( 'fields' => array ( 'Event.id' , 'Event.threat_level_id' , 'Event.orgc_id' , 'Event.uuid' ))),
2016-09-15 17:44:59 +02:00
'group' => array ( 'Attribute.type' , 'Attribute.value' . $valueField ), // fields to GROUP BY
2016-08-23 14:06:06 +02:00
)
);
2016-09-15 17:44:59 +02:00
$orgs = $this -> Event -> Orgc -> find ( 'list' , array (
'fields' => array ( 'Orgc.id' , 'Orgc.name' )
));
2016-09-16 14:55:25 +02:00
return $export -> export ( $attributes , $orgs , $valueField , $intel , $whitelist , $instanceString );
2016-08-23 14:06:06 +02:00
}
2016-09-16 16:49:54 +02:00
public function brozip ( $user , $tags , $eventId , $allowNonIDS , $from , $to , $last , $jobId = false ) {
App :: uses ( 'BroExport' , 'Export' );
$export = new BroExport ();
$types = array_keys ( $export -> mispTypes );
$typeCount = count ( $types );
if ( $jobId ) {
$this -> Job = ClassRegistry :: init ( 'Job' );
$this -> Job -> id = $jobId ;
if ( ! $this -> Job -> exists ()) {
$jobId = false ;
}
}
$dir = new Folder ( APP . 'tmp/files/' . $this -> Event -> generateRandomFileName (), true , 0750 );
$tmpZipname = DS . " bro_export_tmp.zip " ;
$zip = new File ( $dir -> pwd () . $tmpZipname );
foreach ( $types as $k => $type ) {
$final = $this -> bro ( $user , $type , $tags , $eventId , $allowNonIDS , $from , $to , $last );
$filename = $type . '.intel' ;
$file = new File ( $dir -> pwd () . DS . $filename );
$file -> write ( implode ( PHP_EOL , $final ));
$file -> close ();
$execRetval = '' ;
$execOutput = array ();
exec ( 'zip -gj ' . $zip -> path . ' ' . $dir -> pwd () . '/' . $filename , $execOutput , $execRetval );
if ( $execRetval != 0 ) { // not EXIT_SUCCESS
throw new Exception ( 'An error has occured while attempting to zip the intel files.' );
}
$file -> delete (); // delete the original non-zipped-file
if ( $jobId ) {
$this -> Job -> saveField ( 'progress' , $k / $typeCount * 100 );
}
}
$zip -> close ();
return array ( $dir -> pwd (), $tmpZipname );
}
2016-08-23 14:06:06 +02:00
2016-06-04 01:54:19 +02:00
public function generateCorrelation ( $jobId = false , $startPercentage = 0 ) {
2016-06-04 01:14:25 +02:00
$this -> Correlation = ClassRegistry :: init ( 'Correlation' );
$this -> Correlation -> deleteAll ( array ( 'id !=' => 0 ), false );
// get all attributes..
$eventIds = $this -> Event -> find ( 'list' , array ( 'recursive' => - 1 , 'fields' => array ( 'Event.id' )));
$attributeCount = 0 ;
if ( Configure :: read ( 'MISP.background_jobs' ) && $jobId ) {
$this -> Job = ClassRegistry :: init ( 'Job' );
$this -> Job -> id = $jobId ;
$eventCount = count ( $eventIds );
}
2015-12-17 11:01:54 +01:00
foreach ( array_values ( $eventIds ) as $j => $id ) {
2015-12-17 01:25:23 +01:00
if ( $jobId && Configure :: read ( 'MISP.background_jobs' )) {
2015-12-17 11:01:54 +01:00
$this -> Job -> saveField ( 'message' , 'Correlating Event ' . $id );
2015-12-17 10:25:30 +01:00
$this -> Job -> saveField ( 'progress' , ( $startPercentage + ( $j / $eventCount * ( 100 - $startPercentage ))));
2015-12-17 01:25:23 +01:00
}
2015-12-17 13:04:49 +01:00
$event = $this -> Event -> find ( 'first' , array (
'recursive' => - 1 ,
'fields' => array ( 'Event.distribution' , 'Event.id' , 'Event.info' , 'Event.org_id' , 'Event.date' , 'Event.sharing_group_id' ),
2015-12-18 12:43:34 +01:00
'conditions' => array ( 'id' => $id ),
'order' => array ()
2015-12-17 13:04:49 +01:00
));
2016-07-11 20:22:42 +02:00
$attributes = $this -> find ( 'all' , array ( 'recursive' => - 1 , 'conditions' => array ( 'Attribute.event_id' => $id , 'Attribute.deleted' => 0 ), 'order' => array ()));
2015-12-17 01:25:23 +01:00
foreach ( $attributes as $k => $attribute ) {
2015-12-17 13:04:49 +01:00
$this -> __afterSaveCorrelation ( $attribute [ 'Attribute' ], true , $event );
2015-12-17 01:25:23 +01:00
$attributeCount ++ ;
}
}
2015-12-18 12:43:34 +01:00
if ( $jobId && Configure :: read ( 'MISP.background_jobs' )) $this -> Job -> saveField ( 'message' , 'Job done.' );
2016-06-04 01:14:25 +02:00
return $attributeCount ;
2016-06-04 01:54:19 +02:00
}
2016-06-04 01:08:16 +02:00
2016-06-04 01:54:19 +02:00
public function reportValidationIssuesAttributes ( $eventId ) {
2016-06-04 01:14:25 +02:00
$conditions = array ();
if ( $eventId && is_numeric ( $eventId )) $conditions = array ( 'event_id' => $eventId );
// get all attributes..
$attributes = $this -> find ( 'all' , array ( 'recursive' => - 1 , 'fields' => array ( 'id' ), 'conditions' => $conditions ));
// for all attributes..
$result = array ();
$i = 0 ;
foreach ( $attributes as $a ) {
$attribute = $this -> find ( 'first' , array ( 'recursive' => - 1 , 'conditions' => array ( 'id' => $a [ 'Attribute' ][ 'id' ])));
$this -> set ( $attribute );
if ( ! $this -> validates ()) {
$errors = $this -> validationErrors ;
$result [ $i ][ 'id' ] = $attribute [ 'Attribute' ][ 'id' ];
$result [ $i ][ 'error' ] = array ();
foreach ( $errors as $field => $error ) {
$result [ $i ][ 'error' ][ $field ] = array ( 'value' => $attribute [ 'Attribute' ][ $field ], 'error' => $error [ 0 ]);
}
$result [ $i ][ 'details' ] = 'Event ID: [' . $attribute [ 'Attribute' ][ 'event_id' ] . " ] - Category: [ " . $attribute [ 'Attribute' ][ 'category' ] . " ] - Type: [ " . $attribute [ 'Attribute' ][ 'type' ] . " ] - Value: [ " . $attribute [ 'Attribute' ][ 'value' ] . ']' ;
$i ++ ;
}
}
return $result ;
2016-06-04 01:54:19 +02:00
}
2016-06-04 01:08:16 +02:00
2016-06-04 01:54:19 +02:00
// This method takes a string from an argument with several elements (separated by '&&' and negated by '!') and returns 2 arrays
// array 1 will have all of the non negated terms and array 2 all the negated terms
public function dissectArgs ( $args ) {
2016-06-04 01:14:25 +02:00
if ( ! $args ) return array ( null , null );
if ( is_array ( $args )) {
$argArray = $args ;
} 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 ;
}
}
$result [ 0 ] = $accept ;
$result [ 1 ] = $reject ;
return $result ;
2016-06-04 01:54:19 +02:00
}
2016-06-04 01:08:16 +02:00
2016-06-04 01:54:19 +02:00
public function checkForValidationIssues ( $attribute ) {
2016-06-04 01:14:25 +02:00
$this -> set ( $attribute );
if ( $this -> validates ()) {
return false ;
} else {
return $this -> validationErrors ;
}
2016-06-04 01:54:19 +02:00
}
2016-06-04 01:08:16 +02:00
2016-09-04 23:31:24 +02:00
public function checkTemplateAttributes ( $template , $data , $event_id ) {
2016-06-04 01:54:19 +02:00
$result = array ();
$errors = array ();
$attributes = array ();
if ( isset ( $data [ 'Template' ][ 'fileArray' ])) $fileArray = json_decode ( $data [ 'Template' ][ 'fileArray' ], true );
foreach ( $template [ 'TemplateElement' ] as $element ) {
2016-06-04 01:14:25 +02:00
if ( $element [ 'element_definition' ] == 'attribute' ) {
$result = $this -> __resolveElementAttribute ( $element [ 'TemplateElementAttribute' ][ 0 ], $data [ 'Template' ][ 'value_' . $element [ 'id' ]]);
} else if ( $element [ 'element_definition' ] == 'file' ) {
$temp = array ();
if ( isset ( $fileArray )) {
foreach ( $fileArray as $fileArrayElement ) {
if ( $fileArrayElement [ 'element_id' ] == $element [ 'id' ]) {
$temp [] = $fileArrayElement ;
}
}
}
$result = $this -> __resolveElementFile ( $element [ 'TemplateElementFile' ][ 0 ], $temp );
if ( $element [ 'TemplateElementFile' ][ 0 ][ 'mandatory' ] && empty ( $temp ) && empty ( $errors [ $element [ 'id' ]])) $errors [ $element [ 'id' ]] = 'This field is mandatory.' ;
}
if ( $element [ 'element_definition' ] == 'file' || $element [ 'element_definition' ] == 'attribute' ) {
if ( $result [ 'errors' ]) {
$errors [ $element [ 'id' ]] = $result [ 'errors' ];
} else {
foreach ( $result [ 'attributes' ] as & $a ) {
$a [ 'event_id' ] = $event_id ;
$a [ 'distribution' ] = 5 ;
$test = $this -> checkForValidationIssues ( array ( 'Attribute' => $a ));
if ( $test ) {
foreach ( $test [ 'value' ] as $e ) {
$errors [ $element [ 'id' ]] = $e ;
}
} else {
$attributes [] = $a ;
}
}
}
2014-06-25 09:56:33 +02:00
}
2016-06-04 01:54:19 +02:00
}
return array ( 'attributes' => $attributes , 'errors' => $errors );
}
2016-06-04 01:08:16 +02:00
2014-06-25 09:56:33 +02:00
2015-08-04 02:00:21 +02:00
private function __resolveElementAttribute ( $element , $value ) {
$attributes = array ();
$results = array ();
2016-05-20 04:59:33 +02:00
$errors = null ;
2015-08-04 02:00:21 +02:00
if ( ! empty ( $value )) {
if ( $element [ 'batch' ]) {
$values = explode ( " \n " , $value );
foreach ( $values as $v ) {
$v = trim ( $v );
$attributes [] = $this -> __createAttribute ( $element , $v );
}
} else {
$attributes [] = $this -> __createAttribute ( $element , trim ( $value ));
}
foreach ( $attributes as $att ) {
if ( isset ( $att [ 'multi' ])) {
foreach ( $att [ 'multi' ] as $a ) {
$results [] = $a ;
}
} else {
$results [] = $att ;
}
}
} else {
if ( $element [ 'mandatory' ]) $errors = 'This field is mandatory.' ;
}
return array ( 'attributes' => $results , 'errors' => $errors );
}
2016-06-04 01:08:16 +02:00
2015-08-04 02:00:21 +02:00
private function __resolveElementFile ( $element , $files ) {
$attributes = array ();
$errors = null ;
2016-08-17 03:15:57 +02:00
$element [ 'complex' ] = 0 ;
2015-08-04 02:00:21 +02:00
if ( $element [ 'malware' ]) {
$element [ 'type' ] = 'malware-sample' ;
2016-08-17 03:15:57 +02:00
$element [ 'to_ids' ] = 1 ;
2015-08-04 02:00:21 +02:00
} else {
$element [ 'type' ] = 'attachment' ;
2016-08-17 03:15:57 +02:00
$element [ 'to_ids' ] = 0 ;
2015-08-04 02:00:21 +02:00
}
2016-06-04 01:10:45 +02:00
foreach ( $files as $file ) {
2016-08-24 15:30:09 +02:00
if ( ! $this -> checkFilename ( $file [ 'filename' ])) {
2015-08-04 02:00:21 +02:00
$errors = 'Filename not allowed.' ;
continue ;
}
if ( $element [ 'malware' ]) {
$malwareName = $file [ 'filename' ] . '|' . hash_file ( 'md5' , APP . 'tmp/files/' . $file [ 'tmp_name' ]);
$tmp_file = new File ( APP . 'tmp/files/' . $file [ 'tmp_name' ]);
2016-05-20 05:15:23 +02:00
if ( ! $tmp_file -> readable ()) {
2015-08-04 02:00:21 +02:00
$errors = 'File cannot be read.' ;
} else {
$element [ 'type' ] = 'malware-sample' ;
$attributes [] = $this -> __createAttribute ( $element , $malwareName );
$attributes [ count ( $attributes ) - 1 ][ 'data' ] = $file [ 'tmp_name' ];
$element [ 'type' ] = 'filename|sha256' ;
$sha256 = $file [ 'filename' ] . '|' . ( hash_file ( 'sha256' , APP . 'tmp/files/' . $file [ 'tmp_name' ]));
$attributes [] = $this -> __createAttribute ( $element , $sha256 );
$element [ 'type' ] = 'filename|sha1' ;
$sha1 = $file [ 'filename' ] . '|' . ( hash_file ( 'sha1' , APP . 'tmp/files/' . $file [ 'tmp_name' ]));
$attributes [] = $this -> __createAttribute ( $element , $sha1 );
}
} else {
$attributes [] = $this -> __createAttribute ( $element , $file [ 'filename' ]);
$tmp_file = new File ( APP . 'tmp/files/' . $file [ 'tmp_name' ]);
2016-05-20 05:15:23 +02:00
if ( ! $tmp_file -> readable ()) {
$errors = 'File cannot be read.' ;
2015-08-04 02:00:21 +02:00
} else {
$attributes [ count ( $attributes ) - 1 ][ 'data' ] = $file [ 'tmp_name' ];
}
}
}
return array ( 'attributes' => $attributes , 'errors' => $errors , 'files' => $files );
}
2014-07-02 16:20:19 +02:00
2016-06-04 01:54:19 +02:00
private function __createAttribute ( $element , $value ) {
2016-06-04 01:14:25 +02:00
$attribute = array (
'comment' => $element [ 'name' ],
'to_ids' => $element [ 'to_ids' ],
'category' => $element [ 'category' ],
'value' => $value ,
);
if ( $element [ 'complex' ]) {
App :: uses ( 'ComplexTypeTool' , 'Tools' );
$complexTypeTool = new ComplexTypeTool ();
$result = $complexTypeTool -> checkComplexRouter ( $value , ucfirst ( $element [ 'type' ]));
if ( isset ( $result [ 'multi' ])) {
$temp = $attribute ;
$attribute = array ();
2016-06-04 15:45:39 +02:00
foreach ( $result [ 'multi' ] as $k => $r ) {
2016-06-04 01:14:25 +02:00
$attribute [ 'multi' ][] = $temp ;
$attribute [ 'multi' ][ $k ][ 'type' ] = $r [ 'type' ];
$attribute [ 'multi' ][ $k ][ 'value' ] = $r [ 'value' ];
}
} else if ( $result != false ) {
$attribute [ 'type' ] = $result [ 'type' ];
$attribute [ 'value' ] = $result [ 'value' ];
} else {
return false ;
}
} else {
$attribute [ 'type' ] = $element [ 'type' ];
}
return $attribute ;
2016-06-04 01:54:19 +02:00
}
2016-06-04 01:08:16 +02:00
2016-06-04 01:54:19 +02:00
public function buildConditions ( $user ) {
2016-06-04 01:14:25 +02:00
$conditions = array ();
if ( ! $user [ 'Role' ][ 'perm_site_admin' ]) {
$eventIds = $this -> Event -> fetchEventIds ( $user , false , false , false , true );
$sgsids = $this -> SharingGroup -> fetchAllAuthorised ( $user );
$conditions = array (
2015-04-13 12:42:26 +02:00
'AND' => array (
'OR' => array (
array (
'AND' => array (
2016-06-04 01:14:25 +02:00
'Event.org_id' => $user [ 'org_id' ],
)
),
array (
'AND' => array (
2016-05-20 04:59:33 +02:00
'Event.id' => $eventIds ,
2015-04-13 12:42:26 +02:00
'OR' => array (
'Attribute.distribution' => array ( '1' , '2' , '3' , '5' ),
'AND ' => array (
'Attribute.distribution' => 4 ,
'Attribute.sharing_group_id' => $sgsids ,
)
)
)
)
)
)
2016-06-04 01:14:25 +02:00
);
}
return $conditions ;
2016-06-04 01:54:19 +02:00
}
2016-06-04 01:08:16 +02:00
2015-08-31 02:32:37 +02:00
// Method that fetches all attributes for the various exports
// very flexible, it's basically a replacement for find, with the addition that it restricts access based on user
2016-06-04 01:10:45 +02:00
// options:
2015-08-31 02:32:37 +02:00
// fields
// contain
// conditions
// order
// group
2016-05-20 04:59:33 +02:00
public function fetchAttributes ( $user , $options = array ()) {
2016-06-04 01:14:25 +02:00
$params = array (
'conditions' => $this -> buildConditions ( $user ),
'recursive' => - 1 ,
'contain' => array (
'Event' => array (
2016-08-23 14:06:06 +02:00
'fields' => array ( 'id' , 'info' , 'org_id' , 'orgc_id' ),
2016-06-04 01:14:25 +02:00
),
),
);
if ( isset ( $options [ 'contain' ])) $params [ 'contain' ] = array_merge_recursive ( $params [ 'contain' ], $options [ 'contain' ]);
2016-08-23 14:06:06 +02:00
else $option [ 'contain' ][ 'Event' ][ 'fields' ] = array ( 'id' , 'info' , 'org_id' , 'orgc_id' );
2016-06-04 01:14:25 +02:00
if ( isset ( $options [ 'fields' ])) $params [ 'fields' ] = $options [ 'fields' ];
if ( isset ( $options [ 'conditions' ])) $params [ 'conditions' ][ 'AND' ][] = $options [ 'conditions' ];
if ( isset ( $options [ 'order' ])) $params [ 'order' ] = $options [ 'order' ];
else ( $params [ 'order' ] = array ());
2016-07-11 20:22:42 +02:00
if ( ! $user [ 'Role' ][ 'perm_sync' ] || ! isset ( $options [ 'deleted' ]) || ! $options [ 'deleted' ]) $params [ 'conditions' ][ 'AND' ][ 'Attribute.deleted' ] = 0 ;
2016-08-24 09:37:22 +02:00
if ( isset ( $options [ 'group' ])) $params [ 'group' ] = array_merge ( array ( 'Attribute.id' ), $options [ 'group' ]);
2016-03-01 15:58:00 +01:00
if ( Configure :: read ( 'MISP.unpublishedprivate' )) $params [ 'conditions' ][ 'AND' ][] = array ( 'OR' => array ( 'Event.published' => 1 , 'Event.orgc_id' => $user [ 'org_id' ]));
2016-06-04 01:14:25 +02:00
$results = $this -> find ( 'all' , $params );
if ( isset ( $options [ 'withAttachments' ]) && $options [ 'withAttachments' ]) {
foreach ( $results as & $attribute ) {
if ( $this -> typeIsAttachment ( $attribute [ 'Attribute' ][ 'type' ])) {
$encodedFile = $this -> base64EncodeAttachment ( $attribute [ 'Attribute' ]);
$attribute [ 'Attribute' ][ 'data' ] = $encodedFile ;
}
}
}
return $results ;
2016-05-20 04:59:33 +02:00
}
2016-06-04 01:08:16 +02:00
2016-05-20 04:59:33 +02:00
// Method gets and converts the contents of a file passed along as a base64 encoded string with the original filename into a zip archive
2015-08-04 02:00:21 +02:00
// The zip archive is then passed back as a base64 encoded string along with the md5 hash and a flag whether the transaction was successful
// The archive is password protected using the "infected" password
// The contents of the archive will be the actual sample, named <md5> and the original filename in a text file named <md5>.filename.txt
2015-10-21 23:44:07 +02:00
public function handleMaliciousBase64 ( $event_id , $original_filename , $base64 , $hash_types , $proposal = false ) {
2016-05-20 04:59:33 +02:00
if ( ! is_numeric ( $event_id )) throw new Exception ( 'Something went wrong. Received a non-numeric event ID while trying to create a zip archive of an uploaded malware sample.' );
2015-10-21 23:44:07 +02:00
if ( $proposal ) {
$dir = new Folder ( APP . " files " . DS . $event_id . DS . 'shadow' , true );
} else {
$dir = new Folder ( APP . " files " . DS . $event_id , true );
}
2015-08-04 02:00:21 +02:00
$tmpFile = new File ( $dir -> path . DS . $this -> generateRandomFileName (), true , 0600 );
$tmpFile -> write ( base64_decode ( $base64 ));
$hashes = array ();
foreach ( $hash_types as $hash ) {
$hashes [ $hash ] = $this -> __hashRouter ( $hash , $tmpFile -> path );
}
$contentsFile = new File ( $dir -> path . DS . $hashes [ 'md5' ]);
rename ( $tmpFile -> path , $contentsFile -> path );
$fileNameFile = new File ( $dir -> path . DS . $hashes [ 'md5' ] . '.filename.txt' );
$fileNameFile -> write ( $original_filename );
$fileNameFile -> close ();
$zipFile = new File ( $dir -> path . DS . $hashes [ 'md5' ] . '.zip' );
2016-06-12 04:43:05 +02:00
exec ( 'zip -j -P infected ' . escapeshellarg ( $zipFile -> path ) . ' ' . escapeshellarg ( $contentsFile -> path ) . ' ' . escapeshellarg ( $fileNameFile -> path ), $execOutput , $execRetval );
2015-08-04 02:00:21 +02:00
if ( $execRetval != 0 ) $result = array ( 'success' => false );
else $result = array_merge ( array ( 'data' => base64_encode ( $zipFile -> read ()), 'success' => true ), $hashes );
$fileNameFile -> delete ();
$zipFile -> delete ();
$contentsFile -> delete ();
return $result ;
}
2016-06-04 01:08:16 +02:00
2015-08-04 02:00:21 +02:00
private function __hashRouter ( $hashType , $file ) {
$validHashes = array ( 'md5' , 'sha1' , 'sha256' );
if ( ! in_array ( $hashType , $validHashes )) return false ;
switch ( $hashType ) {
case 'md5' :
case 'sha1' :
case 'sha256' :
return hash_file ( $hashType , $file );
break ;
}
2016-05-20 04:59:33 +02:00
return false ;
2015-08-04 02:00:21 +02:00
}
2016-06-04 01:08:16 +02:00
2015-08-04 02:00:21 +02:00
public function generateRandomFileName () {
2016-08-25 20:19:16 +02:00
return ( new RandomTool ()) -> random_str ( FALSE , 12 );
2015-08-04 02:00:21 +02:00
}
2016-06-04 01:08:16 +02:00
2015-08-07 12:04:44 +02:00
public function resolveHashType ( $hash ) {
$hashTypes = $this -> hashTypes ;
$validTypes = array ();
$length = strlen ( $hash );
foreach ( $hashTypes as $k => $hashType ) {
$temp = $hashType [ 'lowerCase' ] ? strtolower ( $hash ) : $hash ;
if ( $hashType [ 'length' ] == $length && preg_match ( $hashType [ 'pattern' ], $temp )) $validTypes [] = $k ;
}
return $validTypes ;
}
2016-06-04 01:08:16 +02:00
2015-12-01 15:39:12 +01:00
public function validateAttribute ( $attribute , $context = true ) {
$this -> set ( $attribute );
if ( ! $context ) {
2016-06-04 01:10:45 +02:00
unset ( $this -> validate [ 'event_id' ]);
2015-12-01 15:39:12 +01:00
unset ( $this -> validate [ 'value' ][ 'uniqueValue' ]);
}
if ( $this -> validates ()) return true ;
else {
return $this -> validationErrors ;
}
}
2016-06-04 01:08:16 +02:00
2016-05-07 23:12:09 +02:00
public function restore ( $id , $user ) {
$this -> id = $id ;
if ( ! $this -> exists ()) return 'Attribute doesn\'t exist, or you lack the permission to edit it.' ;
2016-05-10 17:39:27 +02:00
$attribute = $this -> find ( 'first' , array ( 'conditions' => array ( 'Attribute.id' => $id ), 'recursive' => - 1 , 'contain' => array ( 'Event' )));
2016-05-07 23:12:09 +02:00
if ( ! $user [ 'Role' ][ 'perm_site_admin' ]) {
2016-05-10 17:39:27 +02:00
if ( ! ( $attribute [ 'Event' ][ 'orgc_id' ] == $user [ 'org_id' ] && (( $user [ 'Role' ][ 'perm_modify' ] && $attribute [ 'Event' ][ 'user_id' ] != $user [ 'id' ]) || $user [ 'Role' ][ 'perm_modify_org' ]))) {
return 'Attribute doesn\'t exist, or you lack the permission to edit it.' ;
2016-05-07 23:12:09 +02:00
}
}
2016-05-10 17:39:27 +02:00
unset ( $attribute [ 'Attribute' ][ 'timestamp' ]);
2016-07-11 20:22:42 +02:00
$attribute [ 'Attribute' ][ 'deleted' ] = 0 ;
2016-05-10 17:39:27 +02:00
$date = new DateTime ();
$attribute [ 'Attribute' ][ 'timestamp' ] = $date -> getTimestamp ();
if ( $this -> save ( $attribute [ 'Attribute' ])) {
2016-08-17 03:15:57 +02:00
$attribute [ 'Event' ][ 'published' ] = 0 ;
2016-05-10 17:39:27 +02:00
$attribute [ 'Event' ][ 'timestamp' ] = $date -> getTimestamp ();
$this -> Event -> save ( $attribute [ 'Event' ]);
return true ;
}
2016-05-07 23:12:09 +02:00
else return 'Could not save changes.' ;
}
2012-03-15 15:06:45 +01:00
}