#!/usr/bin/perl -X
use warnings;
use strict;
use Socket;
use Data::Dumper;
use Term::ANSIColor qw(:constants);	
use Getopt::Long;
use Net::OpenSSH;
use POSIX qw(strftime);
$| = 1;

my %options = (
	"--host=s"			=>	\my $argHost,
	"--login=s"		=>	\my $argLogin,
	"--password=s"		=>	\my $argPassword,
	"--portssh=s"		=>	\my $argPortSSH,

	"--pingbin=s"		=>	\my $argPingBinary,
	"--hpingbin=s"		=>	\my $argHPingBinary,

	"--log"			=>	\my $argLogToFile,
	"--debug|d"			=>	\my $argDebug,
	"--help|h|?"		=>	\my $argHelp,
);
Getopt::Long::config("no_ignore_case");
GetOptions(%options);
$Net::OpenSSH::debug |= ($argDebug ? 16 : 0);

   if($argHelp) {
	print " Wykrywanie wirusa \".mf\" \@UBNT \n";
	print "  Wersja: 1.0.0 (2016-05-15 01:10)\n";
	print "  Autro: seszu (seba\@kazuko.pl)\n";
	print "  Strona: http://kazuko.pl\n";
	print "\n";
	print "\n";
	print " --host=\"\"\thosty (zakresy IP) oddzielone spacją (192.168.1.1 192.168.1.0/24 192.168.2.0/30)\n";
	print " --login=\"\"\tloginy oddzielone spacją (admin ubnt)\n";
	print " --password=\"\"\thasła oddzielone spacją (admin superhaslo 1234)\n";
	print " --portssh=\"\"\tporty SSH oddzielone spacją (22 1234 2200)\n";
	print "\n";
	print " --pingbin=\"\"\tścieżka do pinga (domyślnie /bin/ping)\n";
	print " --hpingbin=\"\"\tścieżka do hpinga (domyślnie /usr/sbin/hping3)\n";
	print "\n";
	print " --log\t\tzrzuca log do pliku, będącego w katalogu w którym jest skrypt\n";
	print " --help\t\tdrukuje pomoc\n";
	print " --debug\tdebuguje połączenia ssh\n";
	print "\n";
	exit 0;
   }

   if(!$argHost or !$argLogin or !$argPassword or !$argPortSSH) {
	print " Wykrywanie wirusa \".mf\" \@UBNT \n";
	print "\n";
	print " przykład:\n";
	print " perl $0 --host=\"A.A.A.A/Y B.B.B.B/Y\" --login=\"ubnt admin\" --password=\"ubnt haslo\" --portssh=\"22 2200\"\n";
	print "\n";
	print " --help\t\twięcej...\n";
	print "\n";
	exit 1;
   }

my $path = $0;
my @pathARR = split(/\//, $path);
my $ile = @pathARR;
$path =~ s/@pathARR[$ile-1]//;


my $argPingBinary = $argPingBinary || "/bin/ping";
my $argHPingBinary = $argHPingBinary || "/usr/sbin/hping3";


my @HOSTs = ();
my @arrHost = split(/\s/, $argHost);
   foreach my $host (@arrHost) {
	   if($host =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}$/) {
		my @siec = split(/\//, $host);
		my $cidr = @siec[1];
		my $ileIP = ((2**(32-$cidr))-2);
		my $adressLong = ip2long(@siec[0]);

		my $n;
		   for ($n = 1; $n <= $ileIP; $n++) {
			push(@HOSTs, long2ip($adressLong+$n));
		   }
	   } else {
		push(@HOSTs, $host);
	   }
   }


my @LOGINs = split(/\s/, $argLogin);
my @PASSWORDs = split(/\s/, $argPassword);
my @PORTSSHs = split(/\s/, $argPortSSH);


my $knownHosts = "~/.ssh/known_hosts_test";
   if(-f $knownHosts) { unlink($knownHosts); }
my $logFile = "$path/log.".strftime('%Y%m%d%H%M',localtime).".txt";


   foreach my $host (@HOSTs) {
	print BOLD WHITE, $host, RESET; print "\t";

	my $ping = ping($argPingBinary, "3", $host);
	   if($ping eq "U" or !$ping) {
		print RED, "host nieosiagalny", RESET; print "\n";
		   if($argLogToFile) { plikDopisz($logFile, $host."\thost nieosiagalny\n"); }
		next;
	   }


	my $portSSHk;
	   foreach my $portSSH (@PORTSSHs) {
		my $HpingSSH = qx($argHPingBinary -S -c 3 -p $portSSH $host 2> /dev/null);
		   if($HpingSSH =~ /flags\=RA/ or !($HpingSSH =~ /flags\=SA/)) {
			print RED, $portSSH, RESET; print "\t";
		   } else {
			print GREEN, $portSSH, RESET; print "\t";
			$portSSHk = $portSSH;
		   }
	   }
	   if(!$portSSHk) {
		print RED, "zamkniete wszystkie porty", RESET; print "\n";
		   if($argLogToFile) { plikDopisz($logFile, $host."\tzamkniete wszystkie porty\n"); }
		next;
	   }


	my $ssh;
	   foreach my $login (@LOGINs) {
		   foreach my $password (@PASSWORDs) {
			$ssh = Net::OpenSSH->new($host, user => $login, password => $password, port => $portSSHk, timeout => 30, kill_ssh_on_timeout => 30, master_stderr_discard => 1, master_opts => [-o => "UserKnownHostsFile=$knownHosts", -o => "StrictHostKeyChecking=no"]);
			   if(!$ssh->error) { last; }
		   }
		   if(!$ssh->error) { last; }
	   }

	   if(!$ssh->error) {
		my %MCAStatus;
		my ($done, $err) = trim($ssh->capture2("cat /etc/board.info"));

		   foreach my $linia (split(/\n/, $done)) { if($linia) {
			   if($linia =~ /deviceName\=/) {
				   foreach my $linia2 (split(/\,/, $linia)) { if($linia2) {
					my ($key, $val) = split(/\=/, trim($linia2));
					$MCAStatus{trim($key)} = trim($val);
				   } }
			   } else {
				my ($key, $val) = split(/\=/, trim($linia));
				$MCAStatus{trim($key)} = trim($val);
			   }
		   } }

		   if($MCAStatus{"board.name"}) {
			my $zainfekowany = 0;
			my ($ls, $err) = trim($ssh->capture2("ls -a /etc/persistent"));
			   foreach my $ff (split(/\s/, $ls)) {
				   if($ff =~ /.*\.mf.*/) {
					$zainfekowany = 1;
					last;
				   }
			   }
			   if($zainfekowany) {
				print BOLD RED, "ZAINFEKOWANY !!!!!!!!", RESET; print "\n";
				   if($argLogToFile) { plikDopisz($logFile, $host."\tZAINFEKOWANY !!!!!!!!\n"); }

			   } else {
				print BOLD GREEN, "ZDROWY :)", RESET; print "\n";
				   if($argLogToFile) { plikDopisz($logFile, $host."\tZDROWY :)\n"); }
			   }

		   } else {
			print WHITE, "to nie ubiquiti", RESET; print "\n";
			   if($argLogToFile) { plikDopisz($logFile, $host."to nie ubiquiti\n"); }
		   }
		
	   } else {
		print RED, "cos nie tak z loginami/haslami", RESET; print "\n";
		   if($argLogToFile) { plikDopisz($logFile, $host."\tcos nie tak z loginami/haslami\n"); }
	   }
   }







sub trim($) {
 my $string = shift;
 $string =~ s/^\s+//;
 $string =~ s/\s+$//;
 return $string;
}

sub ip2long {
 return unpack('N', inet_aton(shift));
}

sub long2ip {
 return inet_ntoa(pack("N*", shift));
}




sub ping {
 my($pingBinary, $pingCount, $host) = @_; 
 my $ping = 0;

   open(PROCESS, "$pingBinary -c $pingCount -w 1 $host 2>> /dev/null | grep 'icmp_[s|r]eq' | grep time |");
	$ping = <PROCESS>;
   close(PROCESS);
 $ping =~ m/(.*time=)(.*) (ms|usec)/;

   if($2 == "") { $ping = "U"; } elsif($3 eq "usec") { $ping = $2/1000; } else { $ping = $2; }

 return $ping; 
}




sub plikZapisz { 
 my($plik, $co) = @_; 
  open(UCHWYT, '>', $plik) or die "Nie można otworzyć $plik: $!"; 
  print UCHWYT $co; 
  close UCHWYT;
}

sub plikDopisz { 
 my($plik, $co, $gdzie) = @_; 
   # dopisanie u gory
   if($gdzie eq "up") {
	my $odczyt = join("\n", plikCzytaj($plik));
	plikZapisz($plik, "$co\n".$odczyt);

   # dopisanie u dolu
   } else {
	open(UCHWYT, '>>', $plik) or die "Nie można otworzyć $plik: $!"; 
	print UCHWYT $co; 
	close UCHWYT; 
   }
}
