diff options
author | Michael Weiser <michael.weiser@gmx.de> | 2018-08-24 11:28:14 +0100 |
---|---|---|
committer | Michael Weiser <michael.weiser@gmx.de> | 2018-08-28 16:59:40 +0100 |
commit | c27dbc5724b9db0ab0a9fd6dd52294febf106400 (patch) | |
tree | 48e0362301cbf4cbe724b79bb16f6370ddb3ca8c | |
parent | 8140fb0e975b0f0ff194a049009c34f02596362e (diff) |
Switch to JSON protocol on amavis socket
Expect metadata JSON encoded via socket instead of going searching for
metadata files. This should also eliminate any need for chown2me.
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | MANIFEST.in | 1 | ||||
-rw-r--r-- | README.md | 7 | ||||
-rw-r--r-- | amavis/10-ask_peekaboo | 175 | ||||
-rw-r--r-- | bin/chown2me.c | 103 | ||||
-rw-r--r-- | docs/source/config.rst | 11 | ||||
-rw-r--r-- | docs/source/development.rst | 1 | ||||
-rw-r--r-- | peekaboo.conf.sample | 1 | ||||
-rw-r--r-- | peekaboo/config.py | 2 | ||||
-rw-r--r-- | peekaboo/daemon.py | 89 | ||||
-rw-r--r-- | peekaboo/ruleset/engine.py | 10 | ||||
-rw-r--r-- | peekaboo/sample.py | 94 | ||||
-rw-r--r-- | peekaboo/toolbox/files.py | 13 | ||||
-rw-r--r-- | peekaboo/toolbox/sampletools.py | 43 | ||||
-rw-r--r-- | setup.py | 4 | ||||
-rw-r--r-- | test.py | 47 |
16 files changed, 191 insertions, 413 deletions
@@ -1,6 +1,5 @@ *.log *.pyc -chown2me # eclipse stuff .project .pydevproject @@ -15,8 +14,6 @@ chown2me *.db # config files *.conf -# chown2me binary -bin/chown2me # Sphinx output docs/build # build files diff --git a/MANIFEST.in b/MANIFEST.in index b78d9fb..8ca723f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,5 @@ include README.md include LICENSE.txt -include bin/chown2me.c include requirements.txt include peekaboo.conf.sample include systemd/peekaboo.service @@ -31,13 +31,6 @@ Install dependencies pip install -r requirements.txt ``` -Compile ``chown2me`` -```shell -cd bin/ -make chown2me -sudo setcap cap_chown+ep chown2me -``` - Install PeekabooAV ```shell python setup.py install diff --git a/amavis/10-ask_peekaboo b/amavis/10-ask_peekaboo index f9eba70..296ab5a 100644 --- a/amavis/10-ask_peekaboo +++ b/amavis/10-ask_peekaboo @@ -1,101 +1,110 @@ -use strict; -use File::Copy; +############################################################################### +# # +# Peekaboo Extended Email Attachment Behavior Observation Owl # +# # +# 10-ask_peekaboo +############################################################################### +# # +# Copyright (C) 2016-2018 science + computing ag # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or (at # +# your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # +# General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <http://www.gnu.org/licenses/>. # +# # +############################################################################### -# base directory where dump_info() will put its stuff -my $dump_info_tempdir = '/tmp'; +use strict; -# dump_info creates a .info file for every processed attachment that contains -# internal meta information determined by amavis. It can be used by -# av_scanners. E.g. for behavioural analysis checking in sandboxes where the -# original file extension is required. +# define our own JSON-based protocol by plugging into AMaViS' AV control flow. +# Standard ask_daemon call graph: +# +# virus_scan (iterate over active virus scanners) +# -> ask_daemon (decide what protocol routine to use) +# -> run_av (iterate over files, run scanner and collect results) +# -> ask_daemon_internal (protocol routine: communicate with scanner) # -# example: p002.info +# Our call graph: # -# [attachment] -# full_name: : /var/lib/amavis/tmp/amavis-20170427T174709-03863-dIJwSsyE/parts/p002 -# name_declared: : hugo.txt -# type_declared: : text/plain -# type_long: : ASCII text -# type_short: : asc -# size: : 14 -# digest: : fecf3151ca5ce7b9d24defdc140edc0eefaaeaed:text/plain -# attributes: : -# queue_id: : 96C866A02E4 -sub dump_info($$$) { - my ($part, $tempdir, $own_tempdir) = @_; +# virus_scan +# -> ask_peekaboo (force our protocol routine) +# -> run_av +# -> ask_peekaboo_internal (override query to JSON) +# -> ask_daemon_internal +# +# See below for reasoning. - my $full_name = $part->full_name; - my $base_name = $part->base_name; - my $dir_name = $part->dir_name; +# use pure-perl implementation since performance should be enough for our needs +# and it's been a core module since 5.14, avoiding an additional dependency on +# JSON or JSON::XS +use JSON::PP; +# Yes, Amavis has its own minimalist JSON implementation Amavis::JSON. But it +# doesn't seem to do UTF-8 encoding correctly - everything ends up as latin1. - # redirect amavis tempdir into our tempdir but keep intermediate path - # components ->/var/lib/amavis/tmp/amavis-20180822T155830-07760-4DfB2yxI/parts -> - # /tmp/amavis-20180822T155830-07760-4DfB2yxI/parts - $dir_name =~ s|^$tempdir/|$own_tempdir/|; - # remove /parts subdir component from end - $dir_name =~ s|/parts$||; +sub ask_peekaboo_internal { + my ($dummy, $dummy, $names_to_parts, $dummy) = @_; - unless (-d $dir_name || mkdir($dir_name, 0770)) { - Amavis::Util::do_log(-1, "WARN: Couldn't create info dir $dir_name: $!"); - return 0; - } + # extract some additional info for peekaboo from the parts objects + # structure: + # [ { "full_name" => "<path>", "name_declared" => ..., ... }, + # { ... }, + # ... ] + my $metainfo = []; + foreach my $partname (keys %{$names_to_parts}) { + my $pmi = {}; - my $info_file = "$dir_name/$base_name.info"; - my $info_fh; - unless (open($info_fh, ">:encoding(UTF-8)", $info_file)) { - Amavis::Util::do_log(-1, "WARN: Couldn't create info file $info_file: $!"); - return 0; - } + # certain attributes are only known to a global MSGINFO object + for my $field (qw( queue_id )) { + my $val = $Amavis::MSGINFO->$field(); + $pmi->{$field} = $val if (defined($val)); + } - printf $info_fh "[attachment]\n"; - for my $field (qw( - full_name - name_declared - type_declared - type_long - type_short - size - digest - attributes - queue_id - )) { - my $val = $part->can($field) ? $part->$field() : $Amavis::MSGINFO->$field(); - $val = ref $val eq 'ARRAY' ? $val->[-1] : $val; - $val = Amavis::Util::safe_decode_mime($val) if $field eq "name_declared"; - printf $info_fh "%-15s: %s\n", "$field", $val; - } - close $info_fh; + my $part = $names_to_parts->{$partname}; + for my $field (qw( + full_name + name_declared + type_declared + type_long + type_short + size + digest + attributes + )) { + my $val = $part->$field(); + + # name_declared can be an array of names, if so use the last + $val = ref $val eq 'ARRAY' ? $val->[-1] : $val; + $val = Amavis::Util::safe_decode_mime($val) if $field eq "name_declared"; - unless (copy($full_name, $dir_name)) { - Amavis::Util::do_log(-1, "WARN: couldn't copy $full_name to $dir_name"); - return 0; + # do not transfer undef values since they're no good for nothing + $pmi->{$field} = $val if defined($val); + } + + push(@$metainfo, $pmi); } - return 1; + # format the whole thing as JSON, enforcing UTF-8 encoding and override + # AMaViS-expanded query for standard ask_daemon_internal to execute + $_[0] = JSON::PP->new->utf8->encode($metainfo) . "\n"; + Amavis::AV::ask_daemon_internal(@_); } +# force run_av to execute our protocol routine so we can generate the final +# JSON request structure there. We cannot do it here because run_av will expand +# special placeholders {} and * in the query template and corrupt our JSON if +# it contains those, either because of empty hashes formatted as {} or just a +# simple file name containing the sequence. sub ask_peekaboo { - my($bare_fnames, $names_to_parts, $tempdir, $dummy) = @_; - - # default to /tmp but let dump_info_tempdir override - my $own_tempdir = '/tmp'; - $own_tempdir = $dump_info_tempdir if defined $dump_info_tempdir; - - # remove everything after and including last slash (job identifier in e.g. - # /var/lib/amavis/tmp/amavis-20180822T155830-07760-4DfB2yxI) to get amavis - # tempdir - $tempdir =~ s|/+[^/]+$||; - - # dump out some additional info for peekaboo - foreach my $part (values %{$names_to_parts}) { - unless (dump_info($part, $tempdir, $own_tempdir)) { - # signal virus scanning failure if info can't be dumped - return (undef, '', undef); - } - } - - # use standard daemon socket communication to trigger peekaboo - ask_daemon(@_); + $_[4] = \&ask_peekaboo_internal; + Amavis::AV::run_av(@_); } 1; # ensure a defined return value diff --git a/bin/chown2me.c b/bin/chown2me.c deleted file mode 100644 index 543128b..0000000 --- a/bin/chown2me.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - *----------------------------------------------------------------------------- - * - * Peekaboo Extended Email Attachment Behavior Observation Owl - * - * chown2me.c - * - * Copyright (C) 2016-2018 science + computing ag - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - * <http://www.gnu.org/licenses/>. - * - *----------------------------------------------------------------------------- - * - * - * Changes ownership of every directory entry within /tmp that starts with - * "amavis-" to user and group of the user who runs this program. - * - * Deletion of files remains in sample.py since only it knows what to delete and - * no arguments should be passed to this program for security reasons. - * - * - * Compile with - * - * make chown2me - * - * Run the following command as root to set capability to allow chown - * - * sudo setcap cap_chown+ep chown2me - * - */ - - -#include <unistd.h> -#include <dirent.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> - - -int main(){ - - DIR *d; - struct dirent *dir; - char* path = "/tmp/"; - char* prefix = "amavis-"; - char test[strlen(prefix)+1]; - int uid = getuid(); - int gid = getgid(); - - - FILE * logfile_fd = fopen("chown2me.log", "w+"); - if (logfile_fd == NULL) - { - perror("Unable to open / write to logfile"); - return 1; - } - - fprintf(logfile_fd, "Changing to %i:%i\n", uid, gid); - - d = opendir(path); - if (d) { - while ((dir = readdir(d)) != NULL) { - - // copy prefix to test string - strncpy(test, dir->d_name, strlen(prefix)); - - // compare if prefix equals test - if (strcmp(prefix, test) == 0) { - char fullpath[strlen(path)+strlen(dir->d_name)+1]; - fullpath[0]='\0'; - strcat(fullpath,path); - strcat(fullpath,dir->d_name); - fprintf(logfile_fd, "chown for %s\n", fullpath); - // change owner to 1000 - int res = lchown(fullpath, uid, gid); - if (res != 0){ - perror("chown"); - return res; - } - } - } - closedir(d); - fclose(logfile_fd); - } - else { - perror("opendir"); - return 5; - } - - return 0; -} diff --git a/docs/source/config.rst b/docs/source/config.rst index ad95b6a..1a2907b 100644 --- a/docs/source/config.rst +++ b/docs/source/config.rst @@ -107,17 +107,6 @@ Further, email attachments can be supplied to Peekaboo for analysis directly fro The remaining sections cover the setup of these components. -Compile ``chown2me`` --------------------- - -.. code-block:: shell - - cd bin/ - make chown2me - cp chown2me /opt/peekaboo/bin - sudo setcap cap_chown+ep /opt/peekaboo/bin/chown2me - chown peekaboo:amavis /opt/peekaboo/bin/chown2me - Cuckoo ------ Please refer to the Cuckoo documentation available at https://cuckoo.sh/docs/index.html. diff --git a/docs/source/development.rst b/docs/source/development.rst index d4f16ec..5c4367e 100644 --- a/docs/source/development.rst +++ b/docs/source/development.rst @@ -41,6 +41,5 @@ Simply * ``/path/to/your/venv/bin/pip install -r requirements.txt`` * ``/path/to/your/venv/bin/pip install -r dev-requirements.txt`` * Derive your own config from ``peekaboo.conf.sample`` and save it to ``peekaboo.conf`` -* Compile ``chown2me`` as described in the installation chapter. * Run Peekaboo with: ``/path/to/your/venv/bin/python peekaboo_debug.py`` * For command line options run ``/path/to/your/venv/bin/python peekaboo_debug.py --help`` diff --git a/peekaboo.conf.sample b/peekaboo.conf.sample index 1831700..2e7dbb1 100644 --- a/peekaboo.conf.sample +++ b/peekaboo.conf.sample @@ -10,7 +10,6 @@ group : peekaboo socket_file : /opt/peekaboo/peekaboo.sock pid_file : /opt/peekaboo/peekaboo.pid interpreter : /usr/bin/python -chown2me_exec : /opt/peekaboo/bin/chown2me worker_count : 3 sample_base_dir : /tmp job_hash_regex : /var/lib/amavis/tmp/([^/]+)/parts.* diff --git a/peekaboo/config.py b/peekaboo/config.py index 3d6618e..257d3ee 100644 --- a/peekaboo/config.py +++ b/peekaboo/config.py @@ -81,7 +81,6 @@ class PeekabooConfig(object): self.log_format = '%(asctime)s - %(name)s - (%(threadName)s) - ' \ '%(levelname)s - %(message)s' self.interpreter = None - self.chown2me_exec = None self.worker_count = 3 self.sample_base_dir = None self.job_hash_regex = None @@ -115,7 +114,6 @@ class PeekabooConfig(object): self.pid_file = config.get('global', 'pid_file') self.sock_file = config.get('global', 'socket_file') self.interpreter = config.get('global', 'interpreter') - self.chown2me_exec = config.get('global', 'chown2me_exec') self.worker_count = int(config.get('global', 'worker_count')) self.sample_base_dir = config.get('global', 'sample_base_dir') self.job_hash_regex = config.get('global', 'job_hash_regex') diff --git a/peekaboo/daemon.py b/peekaboo/daemon.py index 33182f1..01a23e7 100644 --- a/peekaboo/daemon.py +++ b/peekaboo/daemon.py @@ -33,6 +33,7 @@ import SocketServer import socket import signal from time import sleep +import json from threading import Thread from argparse import ArgumentParser from sdnotify import SystemdNotifier @@ -41,7 +42,7 @@ from peekaboo.config import parse_config, get_config from peekaboo.db import PeekabooDatabase from peekaboo.toolbox.sampletools import ConnectionMap from peekaboo.queuing import JobQueue, create_workers -from peekaboo.sample import make_sample +from peekaboo.sample import Sample from peekaboo.exceptions import PeekabooDatabaseError from peekaboo.toolbox.cuckoo import Cuckoo, CuckooEmbed, CuckooApi @@ -125,40 +126,62 @@ class PeekabooStreamRequestHandler(SocketServer.StreamRequestHandler): """ def handle(self): """ - Handles a analysis request. The path of the directory / file to analyse must - be written to the corresponding socket. - The maximum buffer size is 1024 bytes. + Handles an analysis request. This is expected to be a JSON structure + containing the path of the directory / file to analyse. Structure: + + [ { "full_name": "<path>", + "name_declared": ..., + ... }, + { ... }, + ... ] + + The maximum buffer size is 16 KiB, because JSON incurs some bloat. """ self.request.sendall('Hallo das ist Peekaboo\n\n') - path = self.request.recv(1024).rstrip() - logger.info("Got run_analysis request for %s" % path) - - if not os.path.exists(path): - self.request.sendall( - 'FEHLER: Pfad existiert nicht oder Zugriff verweigert.' - ) - logger.error("ERROR: Path does not exist or no permission to access it.") - else: - for_analysis = [] - if os.path.isfile(path): - sample = make_sample(path, self.request) - if sample: - for_analysis.append(sample) - else: - # walk recursively through entries in the given directory. - for dirname, __, filenames in os.walk(path): - for filename in filenames: - logger.debug("Found file %s" % filename) - f = os.path.join(dirname, filename) - sample = make_sample(f, self.request) - if sample: - for_analysis.append(sample) - - # introduced after an issue where results were reported - # before all files could be added. - for sample in for_analysis: - ConnectionMap.add(self.request, sample) - JobQueue.submit(sample, self.__class__) + request = self.request.recv(1024 * 16).rstrip() + + try: + parts = json.loads(request) + except: + self.request.sendall('FEHLER: Ungueltiges JSON.') + logger.error('Invalid JSON in request.') + return + + if type(parts) not in (list, tuple): + self.request.sendall('FEHLER: Ungueltiges Datenformat.') + logger.error('Invalid data structure.') + return + + for_analysis = [] + for part in parts: + if not part.has_key('full_name'): + self.request.sendall('FEHLER: Unvollstaendige Datenstruktur.') + logger.error('Incomplete data structure.') + return + + path = part['full_name'] + logger.info("Got run_analysis request for %s" % path) + if not os.path.exists(path): + self.request.sendall('FEHLER: Pfad existiert nicht oder ' + 'Zugriff verweigert.') + logger.error('Path does not exist or no permission ' + 'to access it.') + return + + if not os.path.isfile(path): + self.request.sendall('FEHLER: Eingabe ist keine Datei.') + logger.error('Input is not a file') + return + + sample = Sample(path, part, self.request) + for_analysis.append(sample) + logger.debug('Created sample %s' % sample) + + # introduced after an issue where results were reported + # before all files could be added. + for sample in for_analysis: + ConnectionMap.add(self.request, sample) + JobQueue.submit(sample, self.__class__) def run(): diff --git a/peekaboo/ruleset/engine.py b/peekaboo/ruleset/engine.py index f5be989..a235161 100644 --- a/peekaboo/ruleset/engine.py +++ b/peekaboo/ruleset/engine.py @@ -132,7 +132,7 @@ class RulesetEngine(object): def dump_processing_info(sample): """ - Saves the Cuckoo report as HTML + JSON and the meta info file (if available) + Saves the Cuckoo report as HTML + JSON to a directory named after the job hash. """ job_hash = sample.get_job_hash() @@ -143,14 +143,6 @@ def dump_processing_info(sample): logger.debug('Dumping processing info to %s for sample %s' % (dump_dir, sample)) - # meta info file - if sample.has_attr('meta_info_file'): - try: - copyfile(sample.get_attr('meta_info_file'), - os.path.join(dump_dir, filename + '.info')) - except Exception as e: - logger.exception(e) - # Peekaboo's report try: with open(os.path.join(dump_dir, filename + '_report.txt'), 'w+') as f: diff --git a/peekaboo/sample.py b/peekaboo/sample.py index 7e8dd05..bf4e9eb 100644 --- a/peekaboo/sample.py +++ b/peekaboo/sample.py @@ -29,12 +29,13 @@ import re import errno import shutil import logging +import tempfile from datetime import datetime from peekaboo.config import get_config from peekaboo.exceptions import CuckooReportPendingException, \ CuckooAnalysisFailedException -from peekaboo.toolbox.sampletools import SampleMetaInfo, ConnectionMap, next_job_hash -from peekaboo.toolbox.files import chown2me, guess_mime_type_from_file_contents, \ +from peekaboo.toolbox.sampletools import ConnectionMap, next_job_hash +from peekaboo.toolbox.files import guess_mime_type_from_file_contents, \ guess_mime_type_from_filename from peekaboo.toolbox.ms_office import has_office_macros import peekaboo.ruleset as ruleset @@ -43,23 +44,6 @@ import peekaboo.ruleset as ruleset logger = logging.getLogger(__name__) -def make_sample(file, socket): - """ - Create a Sample object from a given file. - - :param file: Path to the file to create a Sample object from. - :param socket: An optional socket to write the report to. - :return: A sample object representing the given file or None if the file does not exist. - """ - logger.debug("Looking at file %s" % file) - if not os.path.isfile(file): - logger.debug('%s is not a file' % file) - return None - s = Sample(file, socket) - logger.debug('Created sample %s' % s) - return s - - class Sample(object): """ This class handles and describes samples to be analysed by Peekaboo. @@ -74,11 +58,10 @@ class Sample(object): @author: Felix Bauer @author: Sebastian Deiss """ - def __init__(self, file_path, sock=None): + def __init__(self, file_path, metainfo = {}, sock=None): self.__path = file_path self.__config = get_config() self.__db_con = self.__config.get_db_con() - self.__meta_info = None self.__wd = None self.__filename = os.path.basename(self.__path) # A symlink that points to the actual file named @@ -90,7 +73,14 @@ class Sample(object): # Additional attributes for a sample object (e. g. meta info) self.__attributes = {} self.initialized = False - self.meta_info_loaded = False + + for field in metainfo: + logger.debug('meta_info_%s = %s' % (field, metainfo[field])) + + # JSON will transfer null/None values but we don't want them as + # attributes in that case + if metainfo[field] is not None: + self.set_attr('meta_info_' + field, metainfo[field]) def init(self): """ @@ -108,18 +98,19 @@ class Sample(object): logger.debug("initializing sample") job_hash = self.get_job_hash() - self.__wd = os.path.join(self.__config.sample_base_dir, job_hash) - - chown2me() - - meta_info_file = os.path.join(self.__wd, self.__filename + '.info') - self.set_attr('meta_info_file', meta_info_file) - self.load_meta_info(meta_info_file) - + self.__wd = tempfile.mkdtemp(prefix = job_hash, + dir = self.__config.sample_base_dir) + + # create a symlink to submit the file with the correct file extension + # to cuckoo via submit.py. + self.__symlink = os.path.join(self.__wd, + '%s.%s' % (self.sha256sum, self.file_extension)) + logger.debug('ln -s %s %s' % (self.__path, self.__symlink)) try: - self.__create_symlink() + os.symlink(self.__path, self.__symlink) except OSError: pass + self.initialized = True # Add sample to database with state 'inProgress' if the sample is unknown @@ -202,18 +193,6 @@ class Sample(object): logger.debug("Job hash for this sample: %s" % job_hash) return job_hash - def load_meta_info(self, meta_info_file): - try: - self.__meta_info = SampleMetaInfo(meta_info_file) - logger.debug('Parsing meta info file %s for file %s' % (meta_info_file, self.__path)) - # Add the information from the dump info file as attributes to the sample object. - for info in self.__meta_info.get_all().items('attachment'): - logger.debug('meta_info_%s = %s' % (info[0], info[1])) - self.set_attr('meta_info_' + info[0], info[1]) - self.meta_info_loaded = True - except Exception: - logger.info('No metadata available for file %s' % self.__path) - def save_result(self): if self.__db_con.known(self): logger.debug('Known sample info not logged to database') @@ -318,15 +297,14 @@ class Sample(object): # get MIME type from meta info try: - declared_mt = self.__meta_info.get_mime_type() + declared_mt = self.get_attr('meta_info_type_declared') if declared_mt is not None: logger.debug('Sample declared as "%s"' % declared_mt) mime_types.append(declared_mt) except Exception as e: logger.exception(e) declared_mt = None - if self.meta_info_loaded: - logger.error('Cannot get MIME type from meta info although meta info is loaded.') + logger.error('Cannot get MIME type from meta info.') try: declared_filename = self.get_attr('meta_info_name_declared') @@ -409,11 +387,10 @@ class Sample(object): def cuckoo_report(self): if not self.has_attr('cuckoo_report'): try: - file_for_analysis = os.path.join(self.__wd, self.__symlink) - logger.debug("Submitting %s to Cuckoo" % file_for_analysis) + logger.debug("Submitting %s to Cuckoo" % self.__symlink) config = get_config() cuckoo = config.get_cuckoo_obj() - job_id = cuckoo.submit(file_for_analysis) + job_id = cuckoo.submit(self.__symlink) self.set_attr('job_id', job_id) message = 'Erfolgreich an Cuckoo gegeben %s als Job %d\n' \ % (self, job_id) @@ -436,19 +413,6 @@ class Sample(object): self.set_attr('cuckoo_failed', False) return self.get_attr('cuckoo_failed') - def __create_symlink(self): - """ - creates a symlink to submit the file with the correct - file extension to cuckoo via submit.py. - """ - orig = os.path.join(self.__wd, self.__filename) - self.__symlink = '%s/%s.%s' % (self.__wd, - self.sha256sum, - self.file_extension) - logger.debug('ln -s %s %s' % (orig, self.__symlink)) - - os.symlink(orig, self.__symlink) - def __close_socket(self): logger.debug('Closing socket connection.') try: @@ -490,18 +454,14 @@ class Sample(object): logger.exception(e) def __str__(self): - meta_info_loaded = 'no' job_id = -1 - if self.__meta_info: - meta_info_loaded = 'yes' if self.has_attr('job_id'): job_id = self.get_attr('job_id') - return ("<Sample(filename='%s', known='%s', meta_info_loaded='%s', job_id='%d'," + return ("<Sample(filename='%s', known='%s', job_id='%d'," " result='%s', sha256sum='%s')>" % (self.__filename, 'yes' if self.known else 'no', - meta_info_loaded, job_id, self.__result, self.sha256sum)) diff --git a/peekaboo/toolbox/files.py b/peekaboo/toolbox/files.py index 1bb6471..d6897e4 100644 --- a/peekaboo/toolbox/files.py +++ b/peekaboo/toolbox/files.py @@ -34,19 +34,6 @@ from peekaboo.config import get_config logger = logging.getLogger(__name__) -def chown2me(): - """ Acquire ownership of all directories under /tmp with the prefix "amavis-". """ - # TODO: Find a better solution to acquire ownership and only for the directory currently in use. - logger.debug('Invoking chown2me...') - config = get_config() - proc = subprocess.Popen(config.chown2me_exec, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - proc.wait() - if proc.returncode != 0: - logger.error('chown2me exited with code %d' % proc.returncode) - - def guess_mime_type_from_file_contents(file_path): """ Get type from file magic bytes. """ mt = magic.from_file(file_path, mime=True) diff --git a/peekaboo/toolbox/sampletools.py b/peekaboo/toolbox/sampletools.py index 9b17ccc..3a46d5a 100644 --- a/peekaboo/toolbox/sampletools.py +++ b/peekaboo/toolbox/sampletools.py @@ -29,7 +29,6 @@ import string import threading from random import choice from datetime import datetime -from ConfigParser import SafeConfigParser from peekaboo import Singleton from peekaboo.ruleset import Result @@ -37,48 +36,6 @@ from peekaboo.ruleset import Result logger = logging.getLogger(__name__) -class SampleMetaInfo(object): - """ - Additional meta information about a Sample. - - @author: Felix Bauer - @author: Sebastian Deiss - """ - def __init__(self, meta_info_file): - self.__meta_info_file = meta_info_file - self.meta_info = None - self._parse() - - def _parse(self): - """ - Parse a meta information file. - - @see: SafeConfigParser - """ - logger.debug('Parsing sample metadata from %s' % self.__meta_info_file) - self.meta_info = SafeConfigParser() - self.meta_info.read(self.__meta_info_file) - - def get_all(self): - """ - Gets the parsed meta info file. - - :return: A ConfigParser instance for the parsed meta info file. - """ - return self.meta_info - - def get_mime_type(self): - """ - Gets the MIME type parsed from the meta info file field 'type_declared'. - - :return: The MIME type from the meta info file field 'type_declared'. - """ - return self.meta_info.get('attachment', 'type_declared') - - def __str__(self): - return '<SampleMetaInfo(%s)>' % str(self.meta_info) - - class ConnectionMap(Singleton): """ Maps socket objects with one or more samples. @@ -48,10 +48,6 @@ install_requires = [x.strip() for x in all_reqs if 'git+' not in x] dependency_links = [x.strip().replace('git+', '') for x in all_reqs if 'git+' not in x] -# compile chown2me -system('cd bin/ && make chown2me') - - setup( name='PeekabooAV', version=__version__, @@ -44,7 +44,6 @@ class PeekabooDummyConfig(object): self.db_con = None self.job_hash_regex = r'/var/lib/amavis/tmp/([^/]+)/parts.*' self.sample_base_dir = '/tmp' - self.chown2me_exec = 'bin/chown2me' def set_db_con(self, db_con): self.db_con = db_con @@ -181,44 +180,28 @@ class TestSample(unittest.TestCase): self.assertFalse(self.sample.known) def test_sample_attributes_with_meta_info(self): - test_meta_info = '[attachment]\n' |