summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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'
- test_meta_info += 'full_name : /tmp/test.pyc\n'
- test_meta_info += 'name_declared : test.pyc\n'
- test_meta_info += 'type_declared : application/x-bytecode.python\n'
- test_meta_info += 'type_long : application/x-python-bytecode\n'
- test_meta_info += 'type_short : pyc\n'
- test_meta_info += 'size : 200\n'
- test_meta_info += 'digest :\n'
- test_meta_info += 'attributes :\n'
- test_meta_info += 'queue_id :\n'
- with open('./test_meta_info.info', 'w+') as f:
- f.write(test_meta_info)
- self.sample.load_meta_info('./test_meta_info.info')
- self.assertEqual(self.sample.file_extension, 'pyc')
+ sample = Sample('test.pyc', {
+ 'full_name': '/tmp/test.pyc',
+ 'name_declared': 'test.pyc',
+ 'type_declared': 'application/x-bytecode.python',