on an ubuntu 14.04 lts server...
# apt-get install build-essential mail-utils perl
run cpan get the following cpan dependencies:
# cpan
> install Net::DNS
> install Net::Server
> install YAML
> install MIME::Lite::TT
> install Data::Dumper
> install Getopt::Long
> install Net::IP::Match::Regexp
> exit
place perl script and conf in /usr/local/bin/honey or wherever
do a little ln action.
# ln -s /usr/local/honey/honey.conf /etc/honey.conf
set background to 1 in honey.conf to make it turn into a background process.
and... when putting in your ports, if any ports happen to be open when
honey.pl is called, honey.pl will die.
figure them out?
# netstat -tpln
speaking of which look at the honey.conf below, we're going to be opening
a scad of ports. tune the system:
# ulimit -n 70000
# echo "32768 65535" >/proc/sys/net/ipv4/ip_local_port_range
test it
# perl -c honey.pl should return 'OK'
start with
# perl /usr/local/honey.pl --config /etc/honey.conf
if running via /etc/rc.local :
# chmod +x /etc/rc.local
add the line before exit 0:
perl /usr/local/honey.pl --config /etc/honey.conf
##########
# honey.pl
#!/usr/bin/perl
# version 1.3
package Honey;
use MIME::Lite::TT;
use Net::DNS;
use strict;
use warnings;
use Data::Dumper;
use base qw(Net::Server::PreForkSimple);
use YAML;
use Getopt::Long;
use Net::IP::Match::Regexp qw( create_iprange_regexp match_ip );
sub logger($);
my $configfile = "./honey.conf";
GetOptions ("config=s" => \$configfile);
my ($hashref, $arrayref, $string) = YAML::LoadFile( $configfile );
print Dumper($hashref);
my %config = %$hashref;
#############################
### CONFIG
#############################
my $from_email = $config{'from_email'};
my $subject = $config{'subject'};
my $to_email = $config{'to_email'};
my $mailserver = $config{'mailserver'};
my $mail_thres = $config{'mail_thres'};
my $tempfolder = $config{'tempfolder'};
my $lp_ref = $config{'listenports'};
my $background = $config{'background'};
my $ih_ref = $config{'ignorehosts'};
my $logpath = $config{'logpath'};
unless ( 1 &&
defined($from_email) &&
defined($subject) &&
defined($to_email) &&
defined($mailserver) &&
defined($mail_thres) &&
defined($tempfolder) &&
defined($lp_ref) &&
defined($background) &&
defined($ih_ref) &&
1 ) {
die "invalid configuration\n";
}
unless (defined($logpath)) {
print STDERR "No logpath given, will default to /var/log/honey.log";
$logpath = "/var/log/honey.log";
}
logger("honey init");
#############################
### VARS
#############################
my ($i);
my @lports = @$lp_ref;
my @ih = split(",",$ih_ref);
my $ignorehosts = create_iprange_regexp(@ih);
my $tempcache = $tempfolder . "honeycache";
my $tempports = $tempfolder . "honeyports";
my $template = <<TEMPLATE;
Unauthorized connection noted \n\r
Connection details: [% connection_string %] \n\r
Source details: [% srcip %] ([% srcip_dns %]) \n\r
Timestamp: [% timestamp %]
TEMPLATE
############################################
sub post_accept {
#print STDERR "post accept in $$\n";
}
sub process_request {
my $self = shift;
#print STDERR "process request in $$\n";
my $connection_info = $self->{'server'}->{'peeraddr'} . ":" . $self->{'server'}->{'peerport'};
$connection_info = $connection_info . " --> " . $self->{'server'}->{'sockaddr'} . ":" . $self->{'server'}->{'sockport'};
connection_identified( $self->{'server'}->{'peeraddr'}, $connection_info);
}
sub connection_identified ($$) {
my $srcIP = $_[0];
my $connection_info = $_[1];
logger("ok we got a connection from $srcIP");
# RESTORE HASH
my $ref = restore_hash();
my %last_email_timestamp = %$ref;
my $skip_email = 0;
# check if we should ignore this IP
if (match_ip($srcIP, $ignorehosts)) {
logger("ignoring $srcIP!");
$skip_email = 1;
return 0;
}
# email max every $mail_thres secs
my $current_timestamp = time();
if (defined($last_email_timestamp{$srcIP})) {
logger("We have already seen a connection from the host before");
my $diff = $current_timestamp - $last_email_timestamp{$srcIP};
if ( $diff < $mail_thres) {
logger("OK so we saw a connection less than $mail_thres secs ago .. skippin email");
$skip_email = 1;
} else {
logger("but it was a long time ago, diff is $diff");
}
} else {
logger("we have not seen this IP before");
}
$last_email_timestamp{$srcIP} = $current_timestamp;
save_hash(\%last_email_timestamp);
if ($skip_email) { return; };
logger("ok gonna send an email using $mailserver, timeout 60");
# reverse dns
my $srcip_dns = PTR_lookup($srcIP);
# timestamp
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
my $timestamp = sprintf("%4d-%02d-%02d %02d:%02d:%02d\n",$year+1900,$mon+1,$mday,$hour,$min,$sec);
# SEND EMAIL?
my %params;
$params{connection_string} = $connection_info;
$params{srcip_dns} = $srcip_dns;
$params{srcip} = $srcIP;
$params{timestamp} = $timestamp;
my $msg = MIME::Lite::TT->new(
From => $from_email,
To => $to_email,
Subject => $subject,
Template => \$template,
TmplParams => \%params,
);
$msg->send('smtp', $mailserver, Timeout => 60 );
logger("email sent using $mailserver");
}
sub PTR_lookup {
my $tname = shift;
my $type = "Reverse (PTR)";
my $rr;
my $res = new Net::DNS::Resolver;
my $query = $res->query("$tname","PTR");
if ($query) {
foreach $rr ($query->answer) {
next unless $rr->type eq "PTR";
my $ip = $rr->ptrdname;
return ($ip);
}
} else {
my $logstring = "Reverse lookup query failed for $tname : " . $res->errorstring . "\n";
logger($logstring);
return ($tname);
}
}
sub restore_hash() {
my %thash = ();
if (-e $tempcache) {
open(FOO,"<$tempcache") or die;
foreach my $line (<FOO>) {
chomp($line);
my ($ip,$time) = split(":",$line);
$thash{$ip} = $time;
}
close(FOO);
}
return \%thash;
}
sub save_hash($) {
my $hash_ref = $_[0];
my %thash = %$hash_ref;
open(FOO,">$tempcache") or die;
foreach my $key (keys %thash) {
if (defined($thash{$key})) {
print FOO $key . ":" . $thash{$key} . "\n";
}
}
close(FOO);
}
sub logger($) {
my $message = $_[0];
# LOG
open(POO,">>$logpath") or die;
print POO get_date() . ": $message\n";
close(POO);
# STDERR
print STDERR get_date() . ": $message\n";
}
sub get_date () {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
my $timestamp = sprintf("%4d-%02d-%02d %02d:%02d:%02d\n",$year+1900,$mon+1,$mday,$hour,$min,$sec);
chop($timestamp);
return $timestamp;
}
open(FOO,">$tempports") or die;
foreach my $lport (@lports) {
if ($lport =~ /(\d+)-(\d+)/) {
my $startport = $1;
my $stopport = $2;
if ($stopport < $startport) { die "Invalid config, check the range\n"; };
for ($i=$startport;$i<=$stopport;$i++) {
print FOO "port $i\n";
}
} elsif ($lport =~ /^(\d+)/) {
print FOO "port $lport\n";
} else {
logger("Invalid port $lport specified");
}
}
close(FOO);
if ($background) {
Honey->run( background => 1,
conf_file => "$tempports");
} else {
Honey->run(conf_file => "$tempports");
}
##########
# honey.conf
from_email: me@here
to_email: you@there
mailserver: smtpserver
ignorehosts: 10.10.10.10, 0.0.0.0
mail_thres: 60
tempfolder: /tmp/
subject: Unauthorized connection to knockknock
background: 1
logpath: /var/log/honeylog.log
listenports:
- 1-21
- 23-24
- 26-65500
Friday, December 19, 2014
knock know who's there?
sometimes you just want to set up a virtual system to see if there are any scans going on your network.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment