Malware::Parser::NormanSandBoxLive - Perl extension for parsing norman sandbox email digests


Malware documentation Contained in the Malware distribution.

Index


Code Index:

NAME

Top

Malware::Parser::NormanSandBoxLive - Perl extension for parsing norman sandbox email digests

SYNOPSIS use Data::Dumper; use Malware::Parser::NormanSandBoxLive; my $f = 'digest.zip';

Top

  my $n = Malware::Parser::NormanSandBoxLive->new( -zip => $f, -cleanup => 1);

  my (@http,@bn);
  foreach my $m (@{$n->malware()}){
  	if(my @a = $m->returnConnectionsByLayer_array(-type => 'url', -layer => 7, -protocol => 'http')){
  		push(@http,@a) if(@a);
  	}
  	if(my @a = $m->returnConnectionsByLayer_array(-type => 'dns', -layer => 7, -protocol => 'irc')){
  		push(@bn,@a) if(@a);
  	}
  }

  warn Dumper(@http);
  warn Dumper(@bn);

DESCRIPTION

Top

This module is a parser for NormanSandBoxLive email digests (does the web too...but email is better if you can get it). From here you can take the malware behavior and use it to create detection rules etc...

OBJECT METHODS

Top

new()

  my $n = Malware::Parser::NormanSandBoxLive->new(
  	-auto => 1, # default, do we want to auto extract the zip and parse? (yes, rgc, i am that lazy ;-)
  	-zip => $PATH_TO_ZIPFILE,
  	-path => $PATH_TO_SANDBOX_FILE # use this if you dont have the zip, filename must start with 'sandbox_'
  	-cleanup => 1, # clean up the zip file and its extractions after?
  }

extractFromZip()

Uses Archive::Extract to open up the zip file (used internally if you -auto on new()) and sets the path of the sandbox file.

  $n->zip($zipFilePath);
  $n->extractFromZip();

Returns 1 on sucess, dies() on error

parse_txtFile()

Parses the main text file and pushes each malware object it creates into $self->malware()

Returns 1 on success, dies() if the file can't be opened

ACCESSORS / MODIFIERS

Top

zip()

Sets and Returns the zipFile path

path()

Sets and Returns the sandbox_ file path

auto()

Sets and Returns auto property (auto parse)

cleanup()

Sets and Returns the cleanup property (do we unlink() files on parse?)

malware()

Stores an arrayref of malware objects.

Accepts Malware Objects or return ($errstr,undef)

Returns arrayref of malware objects

unknown()

Stores an array of strings that hold unknown classifications

Accepts strings

Returns arrayref of strings

SEE ALSO

Top

Malware,Net::Connection::Simple,Net::Connection::Simple,Time::Timestamp

AUTHOR

Top

Wes Young, <saxguard9-cpan@yahoo.com>

COPYRIGHT AND LICENSE

Top


Malware documentation Contained in the Malware distribution.
package Malware::Parser::NormanSandBoxLive;

use 5.008007;
use strict;
use warnings;
use Malware;
use Archive::Extract;
use Net::Protocol::Simple;
use Net::Connection::Simple;
use Class::ParmList qw(parse_parms);

use constant AUTO => 1; # auto extract and parse?
use constant CLEAN => 1; # auto unlink() files?

our $VERSION = '1.02';

sub new {
	my ($class,%parms) = @_;
	my $self = {};
	bless($self,$class);
	$self->init(%parms);
	return $self;
}

sub init {
	my ($self,%parms) = @_;
	$parms{-auto} = AUTO() if(!$parms{-auto});
	$self->zip(	$parms{-zip});
	$self->path(	$parms{-path});
	$self->cleanup(	$parms{-cleanup});
	$self->auto(	$parms{-auto});

	if($self->auto()){
		$self->extractFromZip() if($self->zip());
		if($self->path()){
			return $self->parse_txtFile();
		}
		else { die 'No Text file found...'."\n";}
	}
}

sub extractFromZip {
	my $self = shift;
	my $fz = Archive::Extract->new( archive => $self->zip() );
	my $ok = $fz->extract() || die $fz->error();
	foreach my $x (@{$fz->files()}){
		if((uc($x)) =~ /SANDBOX_/){
			$self->path($x);
			next;
		}
		unlink($x) if(!defined($self->cleanup()) || $self->cleanup() == 1);
	}
	unlink($self->zip()) if(!defined($self->cleanup()) || $self->cleanup() == 1);
	return 1;
}

sub parse_txtFile {
	my $self = shift;
	my ($ct,$s) = (0,0); # count,start
	my $hr = {};
	my (@a,$m,$tmpSec); # return array, tmp_maleware_placeholder, tmp_section

	open(F, $self->path()) || die 'can not open file: '.$self->path();
	while(<F>){
		chomp();
		next unless length();
		next if(/    \* \*\*IMPORTANT: PLEASE SEND THE SCANNED FILE TO/);
		if($s == 0){
			if(/^Detection:\s.*$/){ $s=1; }
			else { next; }
		}
		if(/^Detection:\s(.*)$/){
			if($ct > 0){
				$m->rawReport($hr->{$ct});
				$self->parser($m);
				$self->malware($m);
			}
			$ct++;
			my $platform = undef;
			for(uc($1)){
				if(/^W32/){
					$platform = 'Win32';
					last;
				}
				$self->unknown($1);
			}
			$m = Malware->new(
				-source		=> 'NormanSandBox',
				-sourceLoc	=> 'NormanEmailDigest',
				-classification	=> $platform,
				-platform	=> $platform,
			);
			next;
		}
		if(/\[\s(.*)\s\]/){
			$tmpSec = $1;
			next;
		}
		if(/\*\s(.*)\./){
			push(@{$hr->{$ct}->{$tmpSec}},$1);
			next;
		}
	}
	close(F);
	unlink($self->path()) if(!defined($self->cleanup()) || $self->cleanup() == 1);
	return 1;
}

# ACCESSORS / MODIFIERS

sub zip {
	my ($self,$v) = @_;
	$self->{_zip} = $v if(defined($v));
	return $self->{_zip};
}

sub path {
	my ($self,$v) = @_;
	$self->{_path} = $v if(defined($v));
	return $self->{_path};
}

sub auto {
	my ($self,$v) = @_;
	$self->{_auto} = $v if(defined($v));
	return $self->{_auto};
}

sub cleanup {
	my ($self,$v) = @_;
	$self->{_cleanup} = $v if(defined($v));
	return $self->{_cleanup};
}

sub malware {
	my ($self,$v) = @_;
	if(defined($v)){
		return ('expecting malware object', undef) if(!(ref($v) =~ /^Malware/));
		push(@{$self->{_malware}},$v);
	}
	return $self->{_malware};
}

sub unknown {
	my ($self,$v) = @_;
	push(@{$self->{_unknown}},$v) if(defined($v));
	return $self->{_unknown};
}

# Internal functions

sub parser {
	my ($self,$m) = @_;
	my $hr = $m->rawReport();
	foreach my $x (keys %$hr) {
		for($x){
			if(/^classification$/){
				$m->classification($hr->{$x});
				next;
			}
			if(/^Network services$/){
				foreach my $y (@{$hr->{$x}}) {
					for($y){
						if(/^Connects to "(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)" on port (\d+) \((\S+)\)/){
							my $c = Net::Connection::Simple->new();

							my $p = Net::Protocol::Simple->new(protocol => 'ip', layer => 3);
							$p->{dip} = $1;
							$c->protocols($p);

							$p = Net::Protocol::Simple->new(protocol => $3, layer => 4);
							$p->{dport} = $2;
							$c->protocols($p);

							$p = Net::Protocol::Simple->new(protocol => 'irc', layer => 7);
							$c->protocols($p);

							$m->connections($c);
							last;
						}
						if(/^Connects to "(\S+\.\S+\.\S+)" on port (\d+) \((\S+)\)/){
							my $c = Net::Connection::Simple->new();
							my $p;

							$p = Net::Protocol::Simple->new(protocol => 'ip', layer => 3);
							$c->protocols($p);

							$p = Net::Protocol::Simple->new(protocol => $3, layer => 4);
							$p->{_dport} = $2;
							$c->protocols($p);

							$p = Net::Protocol::Simple->new(protocol => 'irc', layer => 7);
							$p->{_dns} = $1;
							$c->protocols($p);

							$m->connections($c);
							last;
						}
						if(/^IRC: Joins channel (\S+) with password (\S+)/){
							last;
						}
						if(/^Downloads file from (.*) as.*$/){
							my $c = Net::Connection::Simple->new();
							my $p;

							$p = Net::Protocol::Simple->new(protocol => 'ip', layer => 3);
							$c->protocols($p);

							$p = Net::Protocol::Simple->new(protocol => 'tcp', layer => 4);
							$p->{_dport} = 80;
							$c->protocols($p);

							$p = Net::Protocol::Simple->new(protocol => 'HTTP', layer => 7);
							$p->{_url} = $1;
							$c->protocols($p);

							$m->connections($c);
							last;
						}
					}
				}
				last;
			}
			if(/^General information$/){
				foreach my $y (@{$hr->{$x}}) {
					if($y =~ /^MD5 hash:\s(.*)$/){
						$m->md5sum($1);
						next;
					}
					if($y =~ /^Anti debug\/emulation code present$/){
						$m->antiEmulation(1);
						next;
					}
					if($y =~ /^File length:\s+(\d+)\s(\S+)$/){
						$m->filesize($1);
						$m->filesizeUnits($2);
					}
				}
				last;
			}
			if(/^Changes to registry$/){
				foreach my $y (@{$hr->{$x}}) {
					$m->registry($y);
				}
				last;
			}
			if(/^Changes to filesystem$/){
				foreach my $y (@{$hr->{$x}}) {
					$m->filesystem($y);
				}
				last;
			}
			if(/^Security issues$/){
				foreach my $y (@{$hr->{$x}}) {
					if($y =~ /^Possible backdoor functionality \S+ port (\d+)$/){
						my $p = Net::Protocol::Simple->new(protocol => 'tcp', layer => 4);
						$p->{_sport} = $1;
						$m->backdoors($p);
						next;
					}
					$m->securityIssues($y);
				}
				last;
			}
			if(/^Process\/window information$/){
				foreach my $y (@{$hr->{$x}}) {
					$m->processInfo($y);
				}
				last;
			}
			if(/^Signature Scanning$/){
				my $hr2;
				foreach my $y (@{$hr->{$x}}) {
					if($y =~ /^(.*)\s\(.*\)\s:\s(.*)$/){
						$hr2->{$1} = $2;
					}
				}
				$m->malwareFiles($hr2);
				last;
			}
		}
	}
}
1;
__END__