summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Weiser <michael.weiser@gmx.de>2018-08-24 11:28:14 +0100
committerMichael Weiser <michael.weiser@gmx.de>2018-08-28 16:59:40 +0100
commitc27dbc5724b9db0ab0a9fd6dd52294febf106400 (patch)
tree48e0362301cbf4cbe724b79bb16f6370ddb3ca8c
parent8140fb0e975b0f0ff194a049009c34f02596362e (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--.gitignore3
-rw-r--r--MANIFEST.in1
-rw-r--r--README.md7
-rw-r--r--amavis/10-ask_peekaboo175
-rw-r--r--bin/chown2me.c103
-rw-r--r--docs/source/config.rst11
-rw-r--r--docs/source/development.rst1
-rw-r--r--peekaboo.conf.sample1
-rw-r--r--peekaboo/config.py2
-rw-r--r--peekaboo/daemon.py89
-rw-r--r--peekaboo/ruleset/engine.py10
-rw-r--r--peekaboo/sample.py94
-rw-r--r--peekaboo/toolbox/files.py13
-rw-r--r--peekaboo/toolbox/sampletools.py43
-rw-r--r--setup.py4
-rw-r--r--test.py47
16 files changed, 191 insertions, 413 deletions
diff --git a/.gitignore b/.gitignore
index 8da33c5..4191ce7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/README.md b/README.md
index 8539558..622fcd2 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/setup.py b/setup.py
index 2d56354..7b7693a 100644
--- a/setup.py
+++ b/setup.py
@@ -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__,
diff --git a/test.py b/test.py
index 5eb0123..e0fa968 100644
--- a/test.py
+++ b/test.py
@@ -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'