<commit_before>######################################################################
#
#  Notifications::Email.pm
#  Authors: <NAME> <<EMAIL>>
#           <NAME> <<EMAIL>>
#  University of Twente, The Netherlands
# 
#  LICENSE TERMS: 3-clause BSD license (outlined in license.html) 
#
######################################################################

package SSHCure::Notifications::Email;
use strict;
use warnings;

use MIME::Lite;
use POSIX qw(strftime);
use SSHCure::Utils;

sub handle_notification {
    my (undef, $attacker_ip, $attack, $new_targets, $notification_id) = @_;
    
    # Convert IP number to address
    $attacker_ip = dec2ip($attacker_ip);
    
    # Get name of host running SSHCure
    my $sshcure_host = qx(hostname -f);
    $sshcure_host =~ s/^\s+|\s+\n?$//g;
    
    # Resolve attacker hostname
    my $attacker_hostname = ip2hostname($attacker_ip);
    $attacker_hostname = ($attacker_hostname eq $attacker_ip) ? "" : "($attacker_hostname)"; # Either show the reverse in parentheses, or don't show anything at all
    
    # Get attack phase name (certainty -> name), based on notification config (as the attack may move to a next phase before the notification was sent)
    my $attack_type;
    my @target_list;
    if ($CFG::NOTIFICATIONS{$notification_id}{'filter_type'} eq $CFG::CONST{'NOTIFICATIONS'}{'FILTER_TYPE'}{'ATTACKER'}){
        if ($$attack{'certainty'} >= $CFG::CONST{'NOTIFICATIONS'}{'ATTACK_PHASE'}{'COMPROMISE'}){
            $attack_type = "compromise";
        } elsif ($$attack{'certainty'} >= $CFG::CONST{'NOTIFICATIONS'}{'ATTACK_PHASE'}{'BRUTEFORCE'}){
            $attack_type = "brute-force attack";
        } elsif ($$attack{'certainty'} >= $CFG::CONST{'NOTIFICATIONS'}{'ATTACK_PHASE'}{'SCAN'}){
            $attack_type = "scan attack";
        }
        @target_list = keys(%$new_targets);
    } else {
        # FILTER_TYPE == TARGET
        # Select only those targets to be shown in the notification message that match the notification filter
        my $max_certainty = 0;
        foreach my $target (keys(%$new_targets)) {
            my $target_info = $$attack{'targets'}{$target};
            foreach my $ip_range (split(/,/ ,$CFG::NOTIFICATIONS{$notification_id}{'filter'})) {
                if (ip_addr_in_range($target, $ip_range)) {
                    push(@target_list, $target);
                    $max_certainty = $$target_info{'certainty'} if $$target_info{'certainty'} > $max_certainty;
                    last; # Break only inner loop
                }
            }
        }
        # transform $max_certainty into a string
        if ($max_certainty >= $CFG::CONST{'NOTIFICATIONS'}{'ATTACK_PHASE'}{'COMPROMISE'}){
            $attack_type = "compromise";
        } elsif ($max_certainty >= $CFG::CONST{'NOTIFICATIONS'}{'ATTACK_PHASE'}{'BRUTEFORCE'}){
            $attack_type = "brute-force attack";
        } elsif ($max_certainty >= $CFG::CONST{'NOTIFICATIONS'}{'ATTACK_PHASE'}{'SCAN'}){
            $attack_type = "brute-force attack";
        }
    }
 
    # Sort target list
    @target_list = sort { $a <=> $b } @target_list;
    
    # Convert IP numbers to addresses
    foreach (@target_list) {
        my $target_dec_ip = $_;
        $_ = dec2ip($_);
        $_ .= ' (compromised)' if (exists $$new_targets{$target_dec_ip} && exists $$new_targets{$target_dec_ip}{'compromise_ports'} && $$new_targets{$target_dec_ip}{'compromise_ports'} ne '');<commit_msg>Fixed an erroneous attack type classification in Email.pm<commit_after>######################################################################
#
#  Notifications::Email.pm
#  Authors: <NAME> <<EMAIL>>
#           <NAME> <<EMAIL> <EMAIL>>
#  University of Twente, The Netherlands
# 
#  LICENSE TERMS: 3-clause BSD license (outlined in license.html) 
#
######################################################################

package SSHCure::Notifications::Email;
use strict;
use warnings;

use MIME::Lite;
use POSIX qw(strftime);
use SSHCure::Utils;

sub handle_notification {
    my (undef, $attacker_ip, $attack, $new_targets, $notification_id) = @_;
    
    # Convert IP number to address
    $attacker_ip = dec2ip($attacker_ip);
    
    # Get name of host running SSHCure
    my $sshcure_host = qx(hostname -f);
    $sshcure_host =~ s/^\s+|\s+\n?$//g;
    
    # Resolve attacker hostname
    my $attacker_hostname = ip2hostname($attacker_ip);
    $attacker_hostname = ($attacker_hostname eq $attacker_ip) ? "" : "($attacker_hostname)"; # Either show the reverse in parentheses, or don't show anything at all
    
    # Get attack phase name (certainty -> name), based on notification config (as the attack may move to a next phase before the notification was sent)
    my $attack_type;
    my @target_list;
    if ($CFG::NOTIFICATIONS{$notification_id}{'filter_type'} eq $CFG::CONST{'NOTIFICATIONS'}{'FILTER_TYPE'}{'ATTACKER'}){
        if ($$attack{'certainty'} >= $CFG::CONST{'NOTIFICATIONS'}{'ATTACK_PHASE'}{'COMPROMISE'}){
            $attack_type = "compromise";
        } elsif ($$attack{'certainty'} >= $CFG::CONST{'NOTIFICATIONS'}{'ATTACK_PHASE'}{'BRUTEFORCE'}){
            $attack_type = "brute-force attack";
        } elsif ($$attack{'certainty'} >= $CFG::CONST{'NOTIFICATIONS'}{'ATTACK_PHASE'}{'SCAN'}){
            $attack_type = "scan attack";
        } else {
            # Do nothing
        }

        @target_list = keys(%$new_targets);
    } else {
        # FILTER_TYPE == TARGET
        # Select only those targets to be shown in the notification message that match the notification filter
        my $max_certainty = 0;
        foreach my $target (keys(%$new_targets)) {
            my $target_info = $$attack{'targets'}{$target};
            foreach my $ip_range (split(/,/ ,$CFG::NOTIFICATIONS{$notification_id}{'filter'})) {
                if (ip_addr_in_range($target, $ip_range)) {
                    push(@target_list, $target);
                    $max_certainty = $$target_info{'certainty'} if $$target_info{'certainty'} > $max_certainty;
                    last; # Break only inner loop
                }
            }
        }
        # transform $max_certainty into a string
        if ($max_certainty >= $CFG::CONST{'NOTIFICATIONS'}{'ATTACK_PHASE'}{'COMPROMISE'}){
            $attack_type = "compromise";
        } elsif ($max_certainty >= $CFG::CONST{'NOTIFICATIONS'}{'ATTACK_PHASE'}{'BRUTEFORCE'}){
            $attack_type = "brute-force attack";
        } elsif ($max_certainty >= $CFG::CONST{'NOTIFICATIONS'}{'ATTACK_PHASE'}{'SCAN'}){
            $attack_type = "scan attack";
        } else {
            # Do nothing
        }
    }
 
    # Sort target list
    @target_list = sort { $a <=> $b } @target_list;
    
    # Convert IP numbers to addresses
    foreach (@target_list) {
        my $target_dec_ip = $_;
        $_ = dec2ip($_);
        $_ .= ' (compromised)' if (exists $$new_targets{$target_dec_ip} && exists $$new_targets{$target_dec_ip}{'compromise_ports'} && $$new_targets{$target_dec_ip}{'compromise_ports'} ne '');
{'fraction_non_alphanumeric': 0.18305855599772597, 'fraction_numerical': 0.0014212620807276862, 'mean_word_length': 3.2700242718446604, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3090082', 'n_tokens_mistral': 2296, 'n_tokens_neox': 2188, 'n_words': 476}