Ejemplo n.º 1
0
 public function restSearch($key = 'download', $value = false, $type = false, $category = false, $org = false, $tags = false, $searchall = false, $from = false, $to = false, $last = false, $eventid = false)
 {
     if ($key != 'download') {
         $user = $this->checkAuthUser($key);
     } else {
         if (!$this->Auth->user()) {
             throw new UnauthorizedException('You are not authorized. Please send the Authorization header with your auth key along with an Accept header for application/xml.');
         }
         $user = $this->checkAuthUser($this->Auth->user('authkey'));
     }
     if (!$user) {
         throw new UnauthorizedException('This authentication key is not authorized to be used for exports. Contact your administrator.');
     }
     $value = str_replace('|', '/', $value);
     // request handler for POSTed queries. If the request is a post, the parameters (apart from the key) will be ignored and replaced by the terms defined in the posted json or xml object.
     // The correct format for both is a "request" root element, as shown by the examples below:
     // For Json: {"request":{"value": "7.7.7.7&&1.1.1.1","type":"ip-src"}}
     // For XML: <request><value>7.7.7.7&amp;&amp;1.1.1.1</value><type>ip-src</type></request>
     // the response type is used to determine the parsing method (xml/json)
     if ($this->request->is('post')) {
         if ($this->response->type() === 'application/json') {
             $data = $this->request->input('json_decode', true);
         } elseif ($this->response->type() === 'application/xml') {
             $data = $this->request->data;
         } else {
             throw new BadRequestException('Either specify the search terms in the url, or POST a json array / xml (with the root element being "request" and specify the correct headers based on content type.');
         }
         $paramArray = array('value', 'type', 'category', 'org', 'tags', 'searchall', 'from', 'to', 'last', 'eventid');
         foreach ($paramArray as $p) {
             if (isset($data['request'][$p])) {
                 ${$p} = $data['request'][$p];
             } else {
                 ${$p} = null;
             }
         }
     }
     $simpleFalse = array('value', 'type', 'category', 'org', 'tags', 'searchall', 'from', 'to', 'last', 'eventid');
     foreach ($simpleFalse as $sF) {
         if (!is_array(${$sF}) && (${$sF} === 'null' || ${$sF} == '0' || ${$sF} === false || strtolower(${$sF})) === 'false') {
             ${$sF} = false;
         }
     }
     if ($from) {
         $from = $this->Event->dateFieldCheck($from);
     }
     if ($to) {
         $to = $this->Event->dateFieldCheck($to);
     }
     if ($tags) {
         $tags = str_replace(';', ':', $tags);
     }
     if ($last) {
         $last = $this->Event->resolveTimeDelta($last);
     }
     if ($searchall === 'true') {
         $searchall = "1";
     }
     $conditions['AND'] = array();
     $subcondition = array();
     $this->loadModel('Attribute');
     // add the values as specified in the 2nd parameter to the conditions
     $values = explode('&&', $value);
     if (isset($searchall) && ($searchall == 1 || $searchall === true || $searchall == 'true')) {
         $eventIds = $this->__quickFilter($value);
     } else {
         $parameters = array('value', 'type', 'category', 'org', 'eventid');
         foreach ($parameters as $k => $param) {
             if (isset(${$parameters[$k]})) {
                 if (is_array(${$parameters[$k]})) {
                     $elements = ${$parameters[$k]};
                 } else {
                     $elements = explode('&&', ${$parameters[$k]});
                 }
                 foreach ($elements as $v) {
                     if (substr($v, 0, 1) == '!') {
                         if ($parameters[$k] === 'value' && preg_match('@^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/(\\d|[1-2]\\d|3[0-2]))$@', substr($v, 1))) {
                             $cidrresults = $this->Cidr->CIDR(substr($v, 1));
                             foreach ($cidrresults as $result) {
                                 $subcondition['AND'][] = array('Attribute.value NOT LIKE' => $result);
                             }
                         } else {
                             if ($parameters[$k] === 'org') {
                                 $subcondition['AND'][] = array('Event.' . $parameters[$k] . ' NOT LIKE' => '%' . substr($v, 1) . '%');
                             } elseif ($parameters[$k] === 'eventid') {
                                 $subcondition['AND'][] = array('Attribute.event_id !=' => substr($v, 1));
                             } else {
                                 $subcondition['AND'][] = array('Attribute.' . $parameters[$k] . ' NOT LIKE' => '%' . substr($v, 1) . '%');
                             }
                         }
                     } else {
                         if ($parameters[$k] === 'value' && preg_match('@^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/(\\d|[1-2]\\d|3[0-2]))$@', substr($v, 1))) {
                             $cidrresults = $this->Cidr->CIDR($v);
                             foreach ($cidrresults as $result) {
                                 $subcondition['OR'][] = array('Attribute.value LIKE' => $result);
                             }
                         } else {
                             if ($parameters[$k] === 'org') {
                                 $subcondition['OR'][] = array('Event.' . $parameters[$k] . ' LIKE' => '%' . $v . '%');
                             } elseif ($parameters[$k] === 'eventid') {
                                 $subcondition['OR'][] = array('Attribute.event_id' => $v);
                             } else {
                                 $subcondition['OR'][] = array('Attribute.' . $parameters[$k] . ' LIKE' => '%' . $v . '%');
                             }
                         }
                     }
                 }
                 array_push($conditions['AND'], $subcondition);
                 $subcondition = array();
             }
         }
         // If we are looking for an attribute, we want to retrieve some extra data about the event to be able to check for the permissions.
         if (!$user['User']['siteAdmin']) {
             $temp = array();
             $temp['AND'] = array('Event.distribution >' => 0, 'Attribute.distribution >' => 0, Configure::read('MISP.unpublishedprivate') ? array('Event.published =' => 1) : array());
             $subcondition['OR'][] = $temp;
             $subcondition['OR'][] = array('Event.org' => $user['User']['org']);
             array_push($conditions['AND'], $subcondition);
         }
         // If we sent any tags along, load the associated tag names for each attribute
         if ($tags) {
             $args = $this->Event->Attribute->dissectArgs($tags);
             $this->loadModel('Tag');
             $tagArray = $this->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;
         }
         if ($from) {
             $conditions['AND'][] = array('Event.date >=' => $from);
         }
         if ($to) {
             $conditions['AND'][] = array('Event.date <=' => $to);
         }
         if ($last) {
             $conditions['AND'][] = array('Event.publish_timestamp >=' => $last);
         }
         $params = array('conditions' => $conditions, 'fields' => array('DISTINCT(Attribute.event_id)'));
         $attributes = $this->Attribute->find('all', $params);
         $eventIds = array();
         foreach ($attributes as $attribute) {
             if (!in_array($attribute['Attribute']['event_id'], $eventIds)) {
                 $eventIds[] = $attribute['Attribute']['event_id'];
             }
         }
     }
     if (!empty($eventIds)) {
         $this->loadModel('Whitelist');
         if ((!isset($this->request->params['ext']) || $this->request->params['ext'] !== 'json') && $this->response->type() !== 'application/json') {
             App::uses('XMLConverterTool', 'Tools');
             $converter = new XMLConverterTool();
             $final = "";
             $final .= '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL . '<response>' . PHP_EOL;
             foreach ($eventIds as $currentEventId) {
                 $result = $this->__fetchEvent($currentEventId, null, $user['User']['org'], true);
                 $result = $this->Whitelist->removeWhitelistedFromArray($result, false);
                 $final .= $converter->event2XML($result[0]) . PHP_EOL;
             }
             $final .= '</response>' . PHP_EOL;
             $final_filename = "misp.search.events.results.xml";
             $this->response->body($final);
             $this->response->type('xml');
             $this->response->download($final_filename);
         } else {
             App::uses('JSONConverterTool', 'Tools');
             $converter = new JSONConverterTool();
             $temp = array();
             $final = '{"response":[';
             foreach ($eventIds as $k => $currentEventId) {
                 $result = $this->__fetchEvent($currentEventId, null, $user['User']['org'], true);
                 $final .= $converter->event2JSON($result[0]);
                 if ($k < count($eventIds) - 1) {
                     $final .= ',';
                 }
             }
             $final .= ']}';
             $final_filename = "misp.search.events.results.json";
             $this->response->body($final);
             $this->response->type('json');
             $this->response->download($final_filename);
         }
     } else {
         throw new NotFoundException('No matches.');
     }
     return $this->response;
 }
Ejemplo n.º 2
0
 /**
  * Uploads the event and the associated Attributes to another Server
  * TODO move this to a component
  *
  * @return bool true if success, false or error message if failed
  */
 public function restfullEventToServer($event, $server, $urlPath, &$newLocation, &$newTextBody, $HttpSocket = null)
 {
     if ($event['Event']['distribution'] < 2) {
         // never upload private events
         return 403;
         //"Event is private and non exportable";
     }
     $url = $server['Server']['url'];
     $authkey = $server['Server']['authkey'];
     if (null == $HttpSocket) {
         App::uses('SyncTool', 'Tools');
         $syncTool = new SyncTool();
         $HttpSocket = $syncTool->setupHttpSocket($server);
     }
     $request = array('header' => array('Authorization' => $authkey, 'Accept' => 'application/xml', 'Content-Type' => 'application/xml'));
     $uri = isset($urlPath) ? $urlPath : $url . '/events';
     // LATER try to do this using a separate EventsController and renderAs() function
     $xmlArray = array();
     // rearrange things to be compatible with the Xml::fromArray()
     if (isset($event['Attribute'])) {
         $event['Event']['Attribute'] = $event['Attribute'];
         unset($event['Attribute']);
     }
     if (isset($event['ShadowAttribute'])) {
         unset($event['ShadowAttribute']);
     }
     // cleanup the array from things we do not want to expose
     //unset($event['Event']['org']);
     // remove value1 and value2 from the output
     if (isset($event['Event']['Attribute'])) {
         foreach ($event['Event']['Attribute'] as $key => &$attribute) {
             // do not keep attributes that are private, nor cluster
             if ($attribute['distribution'] < 2) {
                 unset($event['Event']['Attribute'][$key]);
                 continue;
                 // stop processing this
             }
             // Distribution, correct Connected Community to Community in Attribute
             if ($attribute['distribution'] == 2) {
                 $attribute['distribution'] = 1;
             }
             // remove value1 and value2 from the output
             unset($attribute['value1']);
             unset($attribute['value2']);
             // also add the encoded attachment
             if ($this->Attribute->typeIsAttachment($attribute['type'])) {
                 $encodedFile = $this->Attribute->base64EncodeAttachment($attribute);
                 $attribute['data'] = $encodedFile;
             }
             // Passing the attribute ID together with the attribute could cause the deletion of attributes after a publish/push
             // Basically, if the attribute count differed between two instances, and the instance with the lower attribute
             // count pushed, the old attributes with the same ID got overwritten. Unsetting the ID before pushing it
             // solves the issue and a new attribute is always created.
             unset($attribute['id']);
         }
     } else {
         return 403;
     }
     // If we ran out of attributes, or we never had any to begin with, we want to prevent the event from being pushed.
     // It should show up the same way as if the event was not exportable
     if (count($event['Event']['Attribute']) == 0) {
         return 403;
     }
     // Distribution, correct All to Community in Event
     if ($event['Event']['distribution'] == 2) {
         $event['Event']['distribution'] = 1;
     }
     // display the XML to the user
     $xmlArray['Event'][] = $event['Event'];
     App::uses('XMLConverterTool', 'Tools');
     $converter = new XMLConverterTool();
     $data = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL . $converter->event2XML($event) . PHP_EOL;
     // LATER validate HTTPS SSL certificate
     $this->Dns = ClassRegistry::init('Dns');
     if ($this->Dns->testipaddress(parse_url($uri, PHP_URL_HOST))) {
         // TODO NETWORK for now do not know how to catch the following..
         // TODO NETWORK No route to host
         $response = $HttpSocket->post($uri, $data, $request);
         switch ($response->code) {
             case '200':
                 // 200 (OK) + entity-action-result
                 if ($response->isOk()) {
                     $newTextBody = $response->body();
                     $newLocation = null;
                     return true;
                     //return isset($urlPath) ? $response->body() : true;
                 } else {
                     try {
                         // parse the XML response and keep the reason why it failed
                         $xmlArray = Xml::toArray(Xml::build($response->body));
                     } catch (XmlException $e) {
                         return true;
                         // TODO should be false
                     }
                     if (strpos($xmlArray['response']['name'], "Event already exists")) {
                         // strpos, so i can piggyback some value if needed.
                         return true;
                     } else {
                         return $xmlArray['response']['name'];
                     }
                 }
                 break;
             case '302':
                 // Found
                 $newLocation = $response->headers['Location'];
                 $newTextBody = $response->body();
                 return true;
                 //return isset($urlPath) ? $response->body() : $response->headers['Location'];
                 break;
             case '404':
                 // Not Found
                 $newLocation = $response->headers['Location'];
                 $newTextBody = $response->body();
                 return 404;
                 break;
             case '405':
                 return 405;
                 break;
             case '403':
                 // Not authorised
                 return 403;
                 break;
         }
     }
 }