mirror of https://github.com/OISF/suricata
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			156 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Perl
		
	
			
		
		
	
	
			156 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Perl
		
	
# Copyright (C) 2012 Martin Holste
 | 
						|
#
 | 
						|
# You can copy, redistribute or modify this Program under the terms of
 | 
						|
# the GNU General Public License version 2 as published by the Free
 | 
						|
# Software Foundation.
 | 
						|
#
 | 
						|
# 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
 | 
						|
# version 2 along with this program; if not, write to the Free Software
 | 
						|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
# 02110-1301, USA.
 | 
						|
#
 | 
						|
 | 
						|
 | 
						|
package Processor;
 | 
						|
use Moose;
 | 
						|
use Data::Dumper;
 | 
						|
use Module::Pluggable search_path => qw(Processor), sub_name => 'processors';
 | 
						|
use Module::Pluggable search_path => qw(Action), sub_name => 'actions';
 | 
						|
use Log::Log4perl;
 | 
						|
use JSON;
 | 
						|
 | 
						|
has 'conf' => (is => 'rw', isa => 'HashRef', required => 1);
 | 
						|
has 'log' => (is => 'rw', isa => 'Object', required => 1);
 | 
						|
has 'json' => (is => 'ro', isa => 'JSON', required => 1, default => sub { return JSON->new->pretty->allow_blessed });
 | 
						|
 | 
						|
sub BUILD {
 | 
						|
	my $self = shift;
 | 
						|
 | 
						|
	foreach my $processor_plugin ($self->processors){
 | 
						|
		next unless exists $self->conf->{processors}->{$processor_plugin};
 | 
						|
		eval qq{require $processor_plugin};
 | 
						|
		$self->log->info('Using processor plugin ' . $processor_plugin->description);
 | 
						|
	}
 | 
						|
 | 
						|
	foreach my $action_plugin ($self->actions){
 | 
						|
		next unless exists $self->conf->{actions}->{$action_plugin};
 | 
						|
		eval qq{require $action_plugin};
 | 
						|
		$self->log->info('Using action plugin ' . $action_plugin->description);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
sub process {
 | 
						|
	my $self = shift;
 | 
						|
	my $line = shift;
 | 
						|
	#$self->log->debug('got line ' . $line);
 | 
						|
	eval {
 | 
						|
		my $data = $self->json->decode($line);
 | 
						|
		$data->{processors} = {};
 | 
						|
		if($data->{md5}){
 | 
						|
			foreach my $processor_plugin ($self->processors){
 | 
						|
				next unless exists $self->conf->{processors}->{$processor_plugin};
 | 
						|
				my $processor = $processor_plugin->new(conf => $self->conf, log => $self->log, md5 => $data->{md5});
 | 
						|
				$self->log->debug('processing with plugin ' . $processor->description);
 | 
						|
				$data->{processors}->{ $processor->name } = $processor->process();
 | 
						|
			}
 | 
						|
		}
 | 
						|
		#$self->log->debug('data: ' . Dumper($data));
 | 
						|
		foreach my $action_plugin ($self->actions){
 | 
						|
			next unless exists $self->conf->{actions}->{$action_plugin};
 | 
						|
			my $action = $action_plugin->new(conf => $self->conf, log => $self->log, data => $data);
 | 
						|
			$self->log->debug('performing action with plugin ' . $action->description);
 | 
						|
			$action->perform();
 | 
						|
		}
 | 
						|
	};
 | 
						|
	if ($@){
 | 
						|
		$self->log->error('Error: ' . $@ . ', processing line: ' . $line);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
package main;
 | 
						|
use strict;
 | 
						|
use Getopt::Std;
 | 
						|
use FindBin;
 | 
						|
use Config::JSON;
 | 
						|
use File::Tail;
 | 
						|
 | 
						|
# Include the directory this script is in
 | 
						|
use lib $FindBin::Bin;
 | 
						|
 | 
						|
my %Opts;
 | 
						|
getopts('c:', \%Opts);
 | 
						|
 | 
						|
my $conf_file = $Opts{c} ? $Opts{c} : '/etc/suricata/file_processor.conf';
 | 
						|
my $Conf = {
 | 
						|
	logdir => '/tmp',
 | 
						|
	debug_level => 'TRACE',
 | 
						|
	actions => {
 | 
						|
		'Action::Log' => 1,
 | 
						|
		'Action::Syslog' => 1,
 | 
						|
	},
 | 
						|
	processors => {
 | 
						|
		'Processor::Anubis' => 1,
 | 
						|
		'Processor::Malwr' => 1,
 | 
						|
		'Processor::ThreatExpert' => 1,
 | 
						|
	}
 | 
						|
};
 | 
						|
if (-f $conf_file){
 | 
						|
	$Conf = Config::JSON->new( $conf_file );
 | 
						|
	$Conf = $Conf->{config}; # native hash is 10x faster than using Config::JSON->get()
 | 
						|
}
 | 
						|
 | 
						|
# Setup logger
 | 
						|
my $logdir = $Conf->{logdir} ? $Conf->{logdir} : '/var/log/suricata';
 | 
						|
my $debug_level = $Conf->{debug_level} ? $Conf->{debug_level} : 'TRACE';
 | 
						|
my $l4pconf = qq(
 | 
						|
	log4perl.category.App       = $debug_level, File, Screen
 | 
						|
	log4perl.appender.File			 = Log::Log4perl::Appender::File
 | 
						|
	log4perl.appender.File.filename  = $logdir/file_processor.log
 | 
						|
	log4perl.appender.File.syswrite = 1
 | 
						|
	log4perl.appender.File.recreate = 1
 | 
						|
	log4perl.appender.File.layout = Log::Log4perl::Layout::PatternLayout
 | 
						|
	log4perl.appender.File.layout.ConversionPattern = * %p [%d] %F (%L) %M %P %m%n
 | 
						|
	log4perl.filter.ScreenLevel               = Log::Log4perl::Filter::LevelRange
 | 
						|
	log4perl.filter.ScreenLevel.LevelMin  = $debug_level
 | 
						|
	log4perl.filter.ScreenLevel.LevelMax  = ERROR
 | 
						|
	log4perl.filter.ScreenLevel.AcceptOnMatch = true
 | 
						|
	log4perl.appender.Screen         = Log::Log4perl::Appender::Screen
 | 
						|
	log4perl.appender.Screen.Filter = ScreenLevel
 | 
						|
	log4perl.appender.Screen.stderr  = 1
 | 
						|
	log4perl.appender.Screen.layout = Log::Log4perl::Layout::PatternLayout
 | 
						|
	log4perl.appender.Screen.layout.ConversionPattern = * %p [%d] %F (%L) %M %P %m%n
 | 
						|
);
 | 
						|
Log::Log4perl::init( \$l4pconf ) or die("Unable to init logger\n");
 | 
						|
my $Log = Log::Log4perl::get_logger('App') or die("Unable to init logger\n");
 | 
						|
 | 
						|
my $processor = new Processor(conf => $Conf, log => $Log);
 | 
						|
 | 
						|
my $file = $Conf->{file} ? $Conf->{file} : '/var/log/suricata/files-json.log';
 | 
						|
my $tail = new File::Tail(name => $file, maxinterval => 1);
 | 
						|
 | 
						|
while (my $line = $tail->read){
 | 
						|
	$processor->process($line);
 | 
						|
}
 | 
						|
 | 
						|
__END__
 | 
						|
Example config file /etc/suricata/file_processor.conf
 | 
						|
{
 | 
						|
	"logdir": "/var/log/suricata",
 | 
						|
	"debug_level": "INFO",
 | 
						|
	"virustotal_apikey": "xxx"
 | 
						|
	"actions": {
 | 
						|
		"Action::Log": 1
 | 
						|
	},
 | 
						|
	"processors": {
 | 
						|
		"Processor::Anubis": 1,
 | 
						|
		"Processor::Malwr": 1,
 | 
						|
		"Processor::ThreatExpert": 1,
 | 
						|
		"Processor::VirusTotal": 1
 | 
						|
	}
 | 
						|
}
 |