/** * Wrapper for save data. * * @return bool */ public function save() { /* * save evidence into table **/ $this->evidence->save(); /* * call saver **/ $saver = new IncidentsSave(); $saverResult = $saver->save($this->incidents, $this->evidence->id); /* * We've hit a snag, so we are gracefully killing ourselves * after we contact the admin about it. IncidentsSave should never * end with problems unless the mysql died while doing transactions **/ if ($saverResult['errorStatus'] === true) { Log::error(get_class($saver) . ': ' . 'Saver has ended with errors ! : ' . $saverResult['errorMessage']); return false; } $linkedEvents = Event::where('evidence_id', '=', $this->evidence->id); if ($linkedEvents->count() == 0) { Log::info(get_class($saver) . ': ' . 'The evidence submitted was never linked to any ticket, thus removing it from the DB again'); $this->evidence->forceDelete(); } Log::info(get_class($saver) . ': ' . 'Saver has ended without errors'); return true; }
/** * Execute the command * * @return void */ public function handle() { Log::info('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . 'Queued worker is starting the processing of email file: ' . $this->filename); $filesystem = new Filesystem(); $rawEmail = $filesystem->get($this->filename); $parsedMail = new MimeParser(); $parsedMail->setText($rawEmail); // Sanity checks if (empty($parsedMail->getHeader('from')) || empty($parsedMail->getMessageBody())) { Log::warning('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . 'Missing e-mail headers from and/or empty body: ' . $this->filename); $this->alertAdmin(); return; } // Ignore email from our own notification address to prevent mail loops if (preg_match('/' . Config::get('main.notifications.from_address') . '/', $parsedMail->getHeader('from'))) { Log::warning('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . 'Loop prevention: Ignoring email from self ' . Config::get('main.notifications.from_address')); $this->alertAdmin(); return; } // Start with detecting valid ARF e-mail $attachments = $parsedMail->getAttachments(); $arfMail = []; foreach ($attachments as $attachment) { if ($attachment->contentType == 'message/feedback-report') { $arfMail['report'] = $attachment->getContent(); } if ($attachment->contentType == 'message/rfc822') { $arfMail['evidence'] = utf8_encode($attachment->getContent()); } if ($attachment->contentType == 'text/plain') { $arfMail['message'] = $attachment->getContent(); } } /* * Sometimes the mime header does not set the main message correctly. This is ment as a fallback and will * use the original content body (which is basicly the same mime element). But only fallback if we actually * have a RFC822 message with a feedback report. */ if (empty($arfMail['message']) && isset($arfMail['report']) && isset($arfMail['evidence'])) { $arfMail['message'] = $parsedMail->getMessageBody(); } // If we do not have a complete e-mail, then we empty the perhaps partially filled arfMail // which is useless, hence reset to false if (!isset($arfMail['report']) || !isset($arfMail['evidence']) || !isset($arfMail['message'])) { $arfMail = false; } // Asking ParserFactory for an object based on mappings, or die trying $parser = ParserFactory::create($parsedMail, $arfMail); if ($parser !== false) { $parserResult = $parser->parse(); } else { Log::error('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . ': No parser available to handle message from : ' . $parsedMail->getHeader('from') . ' with subject: ' . $parsedMail->getHeader('subject')); $this->alertAdmin(); return; } if ($parserResult !== false && $parserResult['errorStatus'] === true) { Log::error('(JOB ' . getmypid() . ') ' . get_class($parser) . ': ' . ': Parser has ended with fatal errors ! : ' . $parserResult['errorMessage']); $this->alertAdmin(); return; } else { Log::info('(JOB ' . getmypid() . ') ' . get_class($parser) . ': ' . ': Parser completed with ' . $parserResult['warningCount'] . ' warnings and collected ' . count($parserResult['data']) . ' events to save'); } if ($parserResult['warningCount'] !== 0 && Config::get('main.emailparser.notify_on_warnings') === true) { Log::error('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . 'Configuration has warnings set as critical and ' . $parserResult['warningCount'] . ' warnings were detected. Sending alert to administrator'); $this->alertAdmin(); return; } if (count($parserResult['data']) !== 0) { // Call validator $validator = new EventsValidate(); $validatorResult = $validator->check($parserResult['data']); if ($validatorResult['errorStatus'] === true) { Log::error('(JOB ' . getmypid() . ') ' . get_class($validator) . ': ' . 'Validator has ended with errors ! : ' . $validatorResult['errorMessage']); $this->alertAdmin(); return; } else { Log::info('(JOB ' . getmypid() . ') ' . get_class($validator) . ': ' . 'Validator has ended without errors'); } /** * save evidence into table **/ $evidence = new Evidence(); $evidence->filename = $this->filename; $evidence->sender = $parsedMail->getHeader('from'); $evidence->subject = $parsedMail->getHeader('subject'); $evidence->save(); /** * call saver **/ $saver = new EventsSave(); $saverResult = $saver->save($parserResult['data'], $evidence->id); /** * We've hit a snag, so we are gracefully killing ourselves * after we contact the admin about it. EventsSave should never * end with problems unless the mysql died while doing transactions **/ if ($saverResult['errorStatus'] === true) { Log::error('(JOB ' . getmypid() . ') ' . get_class($saver) . ': ' . 'Saver has ended with errors ! : ' . $saverResult['errorMessage']); $this->alertAdmin(); return; } else { Log::info('(JOB ' . getmypid() . ') ' . get_class($saver) . ': ' . 'Saver has ended without errors'); } } else { Log::warning('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . 'Parser did not return any events therefore skipping validation and saving a empty event set'); } Log::info('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . 'Queued worker has ended the processing of email file: ' . $this->filename); }
/** * @param $ticket * @param $account */ private function replayTicket($ticket, $account) { // Create the ticket as usual $newTicket = $this->createTicket($ticket, $account); // Now this is the little magic, we need to calculate the offset and make sure that the first // and lastseen moments exactly match and the increments between those events are within that // same timeframe, but NOT duplicate. $firstSeen = (int) $ticket->FirstSeen; $lastSeen = (int) $ticket->LastSeen; $elapsed = $lastSeen - $firstSeen; $step = (int) round($elapsed / $ticket->ReportCount); $offset = ['first' => $firstSeen, 'last' => $lastSeen, 'elapsed' => $elapsed, 'step' => $step]; for ($counter = 0; $counter <= $ticket->ReportCount; $counter++) { $offset[$counter] = $firstSeen + $counter * $step; } // Make sure we end at the right point in time end($offset); $key = key($offset); $offset[$key] = $lastSeen; // Now recreate all the events for ($counter = 0; $counter <= $ticket->ReportCount; $counter++) { // Build new evidence file and write the evidence into the archive $evidence = new EvidenceSave(); $evidenceData = ['createdBy' => '*****@*****.**', 'receivedOn' => time(), 'submittedData' => json_decode(json_encode($ticket), true), 'attachments' => []]; if (!empty($attachment)) { $evidenceData['attachments'][0] = $attachment; } $evidenceFile = $evidence->save(json_encode($evidenceData)); // Save the file reference into the database $evidenceSave = new Evidence(); $evidenceSave->filename = $evidenceFile; $evidenceSave->sender = '*****@*****.**'; $evidenceSave->subject = 'Migrated evidence with a little magic'; $evidenceSave->save(); // Write the event $newEvent = new Event(); $newEvent->evidence_id = $evidenceSave->id; $newEvent->information = $ticket->Information; $newEvent->source = $ticket->Source; $newEvent->ticket_id = $newTicket->id; $newEvent->timestamp = $offset[$counter]; // Validate the model before saving $validator = Validator::make(json_decode(json_encode($newEvent), true), Event::createRules()); if ($validator->fails()) { $this->error('DevError: Internal validation failed when saving the Event object ' . implode(' ', $validator->messages()->all())); $this->exception(); } $newEvent->save(); } }
/** * Execute the command. * * @return void */ public function handle() { Log::info(get_class($this) . ': Queued worker is starting the processing of email file: ' . $this->filename); $filesystem = new Filesystem(); $rawEmail = $filesystem->get($this->filename); $parsedMail = new MimeParser(); $parsedMail->setText($rawEmail); // Sanity checks if (empty($parsedMail->getHeader('from')) || empty($parsedMail->getMessageBody())) { Log::warning(get_class($this) . 'Validation failed on: ' . $this->filename); $this->exception(); } // Ignore email from our own notification address to prevent mail loops if (preg_match('/' . Config::get('main.notifications.from_address') . '/', $parsedMail->getHeader('from'))) { Log::warning(get_class($this) . 'Loop prevention: Ignoring email from self ' . Config::get('main.notifications.from_address')); $this->exception(); } // Start with detecting valid ARF e-mail $attachments = $parsedMail->getAttachments(); $arfMail = []; foreach ($attachments as $attachment) { if ($attachment->contentType == 'message/feedback-report') { $arfMail['report'] = $attachment->getContent(); } if ($attachment->contentType == 'message/rfc822') { $arfMail['evidence'] = $attachment->getContent(); } if ($attachment->contentType == 'text/plain') { $arfMail['message'] = $attachment->getContent(); } } // If we do not have a complete e-mail, then we empty the perhaps partially filled arfMail // which is useless, hence reset to false if (!isset($arfMail['report']) || !isset($arfMail['evidence']) || !isset($arfMail['message'])) { $arfMail = false; } // Asking GetParser for an object based on mappings, or die trying $parser = GetParser::object($parsedMail, $arfMail); $result = false; $events = false; if ($parser !== false) { $result = $parser->parse(); } else { Log::error(get_class($this) . ': Unable to handle message from: ' . $parsedMail->getHeader('from') . ' with subject: ' . $parsedMail->getHeader('subject')); $this->exception(); } if ($result !== false && $result['errorStatus'] !== true) { Log::info(get_class($parser) . ': Parser as ended without errors. Collected ' . count($result['data']) . ' events to save'); $events = $result['data']; } else { Log::error(get_class($parser) . ': Parser as ended with errors ! : ' . $result['errorMessage']); $this->exception(); } // call validater $validator = new EventsValidate($events); $return = $validator->handle(); if ($return['errorStatus'] === false) { Log::error(get_class($validator) . ': Validator as ended with errors ! : ' . $result['errorMessage']); $this->exception(); } else { Log::info(get_class($validator) . ': Validator as ended without errors'); } // save evidence into table $evidence = new Evidence(); $evidence->filename = $this->filename; $evidence->sender = $parsedMail->getHeader('from'); $evidence->subject = $parsedMail->getHeader('subject'); $evidence->save(); // call saver $saver = new EventsSave($events, $evidence->id); $return = $saver->handle(); if ($return['errorStatus'] === false) { Log::error(get_class($saver) . ': Saver as ended with errors ! : ' . $result['errorMessage']); $this->exception(); } else { Log::info(get_class($saver) . ': Saver as ended without errors'); } }
/** * Execute the command * * @return boolean */ public function handle() { Log::info(get_class($this) . ': ' . 'Queued worker is starting the collector: ' . $this->collector); $collector = collectorFactory::create($this->collector); if (!$collector) { Log::error("The requested collector {$this->collector} could not be started check logs for PID:" . getmypid()); $this->exception(); } $collectorResult = $collector->parse(); if ($collectorResult['errorStatus'] == true) { Log::error("The requested collector {$this->collector} returned an error. check logs for PID:" . getmypid()); $this->exception(); } if (count($collectorResult['data']) !== 0) { // Call validator $validator = new EventsValidate(); $validatorResult = $validator->check($collectorResult['data']); if ($validatorResult['errorStatus'] === true) { Log::error(get_class($validator) . ': ' . 'Validator has ended with errors ! : ' . $validatorResult['errorMessage']); $this->exception(); return; } else { Log::info(get_class($validator) . ': ' . 'Validator has ended without errors'); } /** * save evidence onto disk */ $filesystem = new Filesystem(); $datefolder = Carbon::now()->format('Ymd'); $path = storage_path() . '/mailarchive/' . $datefolder . '/'; $file = Uuid::generate(4) . '.eml'; $filename = $path . $file; if (!$filesystem->isDirectory($path)) { // If a datefolder does not exist, then create it or die trying if (!$filesystem->makeDirectory($path)) { Log::error(get_class($this) . ': ' . 'Unable to create directory: ' . $path); $this->exception(); } chown($path, 'abuseio'); chgrp($path, 'abuseio'); } if ($filesystem->isFile($filename)) { Log::error(get_class($this) . ': ' . 'File aready exists: ' . $filename); $this->exception(); } if ($filesystem->put($filename, json_encode(['collectorName' => $this->collector, 'collectorData' => $collectorResult])) === false) { Log::error(get_class($this) . ': ' . 'Unable to write file: ' . $filename); $this->exception(); } chown($path . $filename, 'abuseio'); chgrp($path . $filename, 'abuseio'); /** * save evidence into table **/ $evidence = new Evidence(); $evidence->filename = $filename; $evidence->sender = 'abuse@localhost'; $evidence->subject = "CLI Collector {$this->collector}"; $evidence->save(); /** * call saver **/ $saver = new EventsSave(); $saverResult = $saver->save($collectorResult['data'], $evidence->id); /** * We've hit a snag, so we are gracefully killing ourselves * after we contact the admin about it. EventsSave should never * end with problems unless the mysql died while doing transactions **/ if ($saverResult['errorStatus'] === true) { Log::error(get_class($saver) . ': ' . 'Saver has ended with errors ! : ' . $saverResult['errorMessage']); $this->exception(); return; } else { Log::info(get_class($saver) . ': ' . 'Saver has ended without errors'); } } else { Log::warning(get_class($this) . ': ' . 'Collector did not return any events therefore skipping validation and saving a empty event set'); } Log::info(get_class($this) . ': ' . 'Queued worker has ended the processing of collector: ' . $this->collector); }