Fwd: logwatch scripts

"Kirk Bauer" <[email protected]>
Newsgroups gmane.comp.log.logwatch.devel
Message-ID <[email protected]>
Thanks Brian, I sent them to the list for you and I assume others will see
value in adding these to the distribution.

---------- Forwarded message ----------
From: Brian Kroth <[email protected]>
Date: Jun 13, 2007 2:50 PM
Subject: logwatch scripts
To: [email protected]

Here's some scripts for you if you'd like to include them - I sent them
previously to the patches/devel lists but I think both were rejected.

mod_security takes Apache's "ErrorLog syslog:facility" data and
generates reports on items matching mod_security rules.  The script
could probably be modified easily enough to work with normal
ErrorLog'ing as well, but this way I can do site wide reporting from a
syslog server.

windows is a rework of the original windows event reporting script.  It
includes some documentation links and just about every security eventid
I could find.

I hope you/others find them useful.

Cheers,
Brian

#!/usr/bin/perl
# mod_security
# 2007-06-13
# Brian Kroth
#
# This file parses through log entries to find those related to mod_security
warnings.
# It then groups them by attacker, message, and target.

use lib "/usr/share/logwatch/lib";
use Logwatch ':all';

my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;

my ($host, $attacker, $details, $ruleid, $msg, $target);

LINE: while (defined($line = <STDIN>)) {
        if ($line =~
/^(\S+\s+){3}(\S+)\s+apache2\[[0-9]+\]:\s+\[error\]\s+\[client\s+(\S+)\]\s+ModSecurity(.+)/)
{
                # These two are always present
                #$host = $2;
                $attacker = $3;

                $details = $4;
                undef $ruleid;
                undef $msg;
                undef $target;

                # ignore these messages
                next LINE if ($details =~ /Connection reset by peer/ ||
$details =~ /robot activity/);

                # Set this if they're available
                if ($details =~ /\[id\s+"([0-9]+)"\]/) {
                        $ruleid = $1;
                }
                if ($details =~ /\[msg\s+"([^"]+)"\]/) {
                        $msg = $1;
                        $msg =~ s/^(.+)\s+Matched signature.+$/$1/;
                }
                if ($details =~ /\[hostname\s+"(\S+)"\]/) {
                        $target = $1;
                }

                #print "DEBUG ModSecurity \thost:$host
\tattacker:".LookupIP($attacker)." \truleid:$ruleid \tmsg:$msg
\ttarget:$target\n";

                # First group by attacker as best we can
                if (defined($msg)) {
                        if (defined($target)) {
                                $byAttacker{$attacker}{$msg}{$target}++;
                        }
                        else {
                                $byAttacker{$attacker}{$msg}{"-"}++;
                        }
                }
                elsif (defined($ruleid)) {
                        if (defined($target)) {
                                $byAttacker{$attacker}{$ruleid}{$target}++;
                        }
                        else {
                                $byAttacker{$attacker}{$ruleid}{"-"}++;
                        }
                }
                elsif (defined($target)) {
                        $byAttacker{$attacker}{"-"}{$target}++;
                }
                else {
                        $byAttacker{$attacker}{"-"}{"-"}++;
                }

                # Next group by rule as best we can.
                if (defined($msg)) {
                        if (defined($target)) {
                                $byRule{$msg}{$target}{$attacker}++;
                        }
                        else {
                                $byRule{$msg}{"-"}{$attacker}++;
                        }
                }
                elsif (defined($ruleid)) {
                        if (defined($target)) {
                                $byRule{$ruleid}{$target}{$attacker}++;
                        }
                        else {
                                $byRule{$ruleid}{"-"}{$attacker}++;
                        }

                }
                else {
                        if (defined($target)) {
                                $byRule{"-"}{$target}{$attacker}++;
                        }
                        else {
                                $byRule{"-"}{"-"}{$attacker}++;
                        }
                }


                # Finally, group by target as best we can.
                if (defined($target)) {
                        if (defined($msg)) {
                                $byTarget{$target}{$msg}{$attacker}++;
                        }
                        elsif (defined($ruleid)) {
                                $byTarget{$target}{$ruleid}{$attacker}++;
                        }
                        else {
                                $byTarget{$target}{"-"}{$attacker}++;
                        }
                }
                else {
                        if (defined($msg)) {
                                $byTarget{"-"}{$msg}{$attacker}++;
                        }
                        elsif (defined($ruleid)) {
                                $byTarget{"-"}{$ruleid}{$attacker}++;
                        }
                        else {
                                $byTarget{"-"}{"-"}{$attacker}++;
                        }
                }
        }
}

if (keys %byAttacker) {
        printLevel3("ModSecurity: Reporting by Attacker, Rule, Target",
\%byAttacker);
}

if (keys %byRule) {
        printLevel3("ModSecurity: Reporting by Rule, Target, Attacker",
\%byRule);
}

if (keys %byTarget) {
        printLevel3("ModSecurity: Reporintg by Target, Rule, Attacker",
\%byTarget);
}

# Prints a hash that's three levels deep in a generic hierarchical manor
sub printLevel3 {
        my $msg = $_[0];
        my %data = %{$_[1]};

        print "\n\t---- $msg ----\n\n";
        foreach $first (sort(keys %data)) {
                $first_total = 0;
                foreach $second (keys %{$data{$first}}) {
                        $second_total{$second} = 0;
                        foreach $third (keys %{$data{$first}{$second}}) {
                                $second_total{$second} +=
$data{$first}{$second}{$third};
                        }
                        $first_total += $second_total{$second};
                }

                print "\t" . LookupIP($first) . ":  $first_total Time(s)\n";
                foreach $second (sort(keys %{$data{$first}})) {
                        print "\t\t" . LookupIP($second) .
":  $second_total{$second} Time(s)\n";
                        foreach $third (sort(keys
%{$data{$first}{$second}})) {
                                print "\t\t\t" . LookupIP($third) .
"  $data{$first}{$second}{$third} Time(s)\n";
                        }
                }
                print "\n";
        }
}

#!/usr/bin/perl
# windows
# 2007-06-04
# Brian Kroth
#
# This is a logwatch script that looks at a log file composed of windows
auth
# security logs counts the number of times a user failed to login and
# optionally the number times they succesfully logged in and some other
account
# creation/modification audits.
#
# See the following sites for event id documentation:
#
http://www.microsoft.com/technet/prodtechnol/windowsserver2003/technologies/security/bpactlck.mspx
# http://support.microsoft.com/?id=299475
# http://support.microsoft.com/?id=301677

use lib "/usr/share/logwatch/lib";
use Logwatch ':all';

my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 4;

my ($month, $day, $time, $host, $process, $eventid, $msg);

# Loop through the given input and parse it first to make sure we need to,
# then to sort it into various categories.
while (defined($line = <STDIN>)) {

        ($month, $day, $time, $host, $process, $eventid, $msg) =
split(/\s+/, $line, 7);

        chomp($host);
        chomp($process);
        chomp($eventid);
        chomp($msg);

        if ($process =~ /security\[failure\]/) { # failure events

                # First count the number of failed logins - we always want
that.
                # Events 529 - 537, 539
                if (($eventid >= 529 && $eventid <= 537) || $eventid == 539
|| $eventid == 680) {
                        $msg =~ /(User Name|Logon
account):\s*(\S+)\s+.+(Address|Workstation( Name)?):\s*\\{0,2}(\S+)/;
                        # print "DEBUG Logon Failure: name:$2 source:$4\n";
                        $loginFail{$2}{$5}++;
                }

                # TODO: Add reporting for other security audits and print
the data

                # IKE Failures: Events 544 - 547
                #elsif ($eventid >= 544 && $eventid <= 547 && $line =~
/some_meaningful_pattern/) {
                #}

                elsif ($eventid == 547) { # IKE security association
negotiation failed
                        $msg =~ /IKE Peer Addr\s+(\S+)\s+.+Failure
Reason:\s*(.+)\s+Extra Status:/;
                        #print "DEBUG IKE security association negotiation
failed: host:$host peer:$1 reason:$2\n";
                        $ikeSecNegFail{$host}{$1}{$2}++;
                }

                elsif ($eventid == 644) { # User Account Locked Out
                        $msg =~ /Target Account Name:\s*(\S+)\s+.+Caller
User Name:\s*(\S+)/;
                        #print "DEBUG User Account Locked Out: $1 on $2 by
$3\n";
                        $lockedOut{$host}{$1}{$2}++;
                }

                elsif ($eventid == 675 || $eventid == 676 || $eventid ==
677) { # Kerberos authentication failed
                        $msg =~ /User Name:\s*(\S+)\s+.+Client
Address:\s*(\S+)/;
                        #print "DEBUG Pre-Authentication failed: $1 on
$2\n";
                        $krbAuthFail{$host}{$1}{$2}++;
                }

                #elsif ($eventid == 681) { # Logon Failure - not used in
Windows 2003/XP
                #       $msg =~ /The logon to
account:\s*(\S+)\s+by:\s*(\S+)\s+from workstation:\s*(\S+)\s+failed/;
                #       print "DEBUG Logon Failure to $1 by $2 from $3\n";
                #       $logonFailure{$1}{$2}{$3}++;
                #}

                elsif ($eventid == 861) { # The Windows Firewall has
detected an application listenin for incomming traffic.
                        $msg =~ /Path:\s*(\S+)\s+.+User
account:\s*(\S+)\s+.+IP protocol:(\S+)\s+Port
number:\s*(\S+)\s+Allowed:\s*(\S+)/;
                        #print "DEBUG Server Application Firewalled: path:$1
account:$2 port:$3 $4 allowed:$5\n";
                        $firewall{$host}{$2}{$1}{$3}{$4}{$5}++;
                }

                else { # unmatched catch all
                        chomp($msg);
                        $unmatchedFail{$eventid . " " . $msg}++;
                }
        }

        elsif ($detail > 3 && $process =~ /security\[success\]/) { # success
events

                if ($eventid == 528 || $eventid == 540 || $eventid == 680) {
# Successful Logon
                        $msg =~ /(User Name|Logon account|Account
Name):\s*(\S+)\s+.+(Address|Workstation( Name)?):\s*\\{0,2}(\S+)/;
                        if ($2 !~ /^-|\S+\$$/) { # ignore machines and
anonymous
                                #print "DEBUG Logon Success name:$2
source:$5\n";
                                $loginSuccess{$2}{$5}++;
                        }
                }

                elsif ($eventid == 517) { # Audit log was cleared.
                        $msg =~ /Primary User Name:\s*(\S+)\s+.*Client User
Name:\s*(\S+)/;
                        # print "DEBUG Audit log cleared: host:$host
primary:$1 client:$2\n";
                        $auditLogCleared{$host}{$1}{$2}++;
                }

                elsif ($eventid == 608) { # User Right Assigned
                        $msg =~ /User Right:\s*(\S+)\s+Assigned
To:\s*(\S+)\s+Assigned By:\s+User Name:\s*(\S+)/;
                        # print "DEBUG Rights Added: right:$1 to:$2
by:$3\n";
                        $rightsAdded{$host}{$3}{$2}{$1}++;
                }
                elsif ($eventid == 609) { # User Right Removed
                        $msg =~ /User Right:\s*(\S+)\s+Removed
From:\s*(\S+)\s+Removed By:\s+User Name:\s*(\S+)/;
                        # print "DEBUG Rights Removed: right:$1 from:$2
by:$3\n";
                        $rightsRemoved{$host}{$3}{$2}{$1}++;
                }

                elsif ($eventid == 610) { # New Trusted Domain
                        $msg =~ /New Trusted Domain\s+Domain(
Name)?:\s*(\S+)\s+.*Established By:\s+User Name:\s*(\S+)/;
                        # print "DEBUG New Trusted Domain: domain:$2 user:$3
host:$host\n";
                        $newDomainTrust{$host}{$2}{$3}++;
                }
                elsif ($eventid == 611) { # Removing Trusted Domain
                        $msg =~ /Removing Trusted Domain\s+Domain(
Name)?:\s*(\S+)\s+.*Established By:\s+User Name:\s*(\S+)/;
                        # print "DEBUG New Trusted Domain: domain:$2 user:$3
host:$host\n";
                        $rmDomainTrust{$host}{$2}{$3}++;
                }

                elsif ($eventid == 612) { # Audit Policy Changed
                        $msg =~ /Changed By:\s+User Name:\s*(\S+)/;
                        # print "DEBUG Audit Policy Changed by $1 on
$host\n";
                        $auditPolChange{$host}{$1}++;
                }

                # Group all account types together - should be clear what's
what.
                elsif ($eventid == 624 || $eventid == 631 || $eventid == 635
|| $eventid == 645
                        || $eventid == 653 || $eventid == 658 || $eventid ==
663) { # Account Created

                        $msg =~ /New Account Name:\s*(\S+)\s+.*Caller User
Name:\s*(\S+)/;
                        #print "DEBUG Account Created: $1 by $2 on $host\n";
                        $newAccount{$host}{$2}{$1}++;
                }
                elsif ($eventid == 625) { # User Account Type Change
                        $msg =~ /Target Account Name:\s*(\S+)\s+.+New
Type:\s*(\S+)\s*Caller User Name:\s*(\S+)/;
                        # print "DEBUG User Account Type Change: $1 to $2 by
$3 on $host\n";
                        $accountTypeChange{$host}{$3}{$1}{$2}++;
                }
                elsif ($eventid == 626) { # User Account Enabled
                        $msg =~ /Target Account Name:\s*(\S+)\s+.+Caller
User Name:\s*(\S+)/;
                        # print "DEBUG User Account Enabled: $1 by $2 on
$host\n";
                        $accountEnabled{$host}{$2}{$1}++;
                }
                elsif ($eventid == 627) { # Change Password Attempt
                        $msg =~ /Target Account Name:\s*(\S+)\s+.+Caller
User Name:\s*(\S+)/;
                        # print "DEBUG Change Password Attempt: $1 by $2 on
$host\n";
                        $changePasswordAttempt{$host}{$2}{$1}++;
                }
                elsif ($eventid == 628) { # User Account password set
                        $msg =~ /Target Account Name:\s*(\S+)\s+.+Caller
User Name:\s*(\S+)/;
                        # print "DEBUG User Account password set: $1 by $2
on $host\n";
                        $passwordSet{$host}{$2}{$1}++;
                }
                elsif ($eventid == 630 || $eventid == 634 || $eventid == 638
|| $eventid == 647
                        || $eventid == 652 || $eventid == 657 || $eventid ==
662 || $eventid == 667) { # User Account Deleted

                        $msg =~ /Target Account Name:\s*(\S+)\s+.+Caller
User Name:\s*(\S+)/;
                        # print "DEBUG Account Deleted: $1 by $2 on
$host\n";
                        $accountDeleted{$host}{$2}{$1}++;
                }

                # Note: This doesn't distinguish between Global and Local
Groups
                elsif ($eventid == 632 || $eventid == 636 || $eventid == 650
|| $eventid == 655
                        || $eventid == 660 || $eventid == 665) { # Group
Member Added

                        $msg =~ /Member Name:\s*(\S+)\s+.+Target Account
Name:\s*(\S+)\s+.+Caller User Name:\s*(\S+)/;
                        # print "DEBUG Group Member Added: $1 to $2 by $3 on
$host\n";
                        $groupMemberAdded{$host}{$2}{$3}{$1}++;
                }
                elsif ($eventid == 633 || $eventid == 637 || $eventid == 651
|| $eventid == 656
                        || $eventid == 661 || $eventid == 666) { # Group
Member Removed

                        $msg =~ /Member Name:\s*(\S+)\s+.+Target Account
Name:\s*(\S+)\s+.+Caller User Name:\s*(\S+)/;
                        #print "DEBUG Group Member Removed: $1 to $2 by $3
on $host\n";
                        $groupMemberRemoved{$host}{$2}{$3}{$1}++;
                }
                elsif ($eventid == 639 || $eventid == 641 || $eventid == 642
|| $eventid == 646 || $eventid == 649
                        || $eventid == 654 || $eventid == 659 || $eventid ==
664 || $eventid == 668) { # Account Changed

                        $msg =~ /Target Account Name:\s*(\S+)\s+.+Caller
User Name:\s*(\S+)/;
                        #print "DEBUG Account Changed: $1 by $2 on $host\n";
                        $accountChanged{$host}{$2}{$1}++;
                }

                elsif ($eventid == 643) { # Domain Policy Changed
                        $msg =~ /Domain Policy Changed:\s*(.+)
modified.+Caller User Name:\s*(\S+)/;
                        #print "DEBUG Domain Policy Changed: $2 on $host to
$1\n";
                        $domainPolicyChanged{$host}{$2}{$1}++;
                }

                elsif ($detail > 5 && $eventid == 672) { # Authentication
Ticket Granted
                        $msg =~ /User Name:\s*(\S+)\s+.+Service
Name:\s*(\S+)\s+.+Client Address:\s*(\S+)/;
                        #print "DEBUG TGT Granted to $1 for $2 from $3\n";
                        $tgtGranted{$host}{$1}{$2}{$3}++;
                }
                elsif ($detail > 5 && $eventid == 673) { # Service Ticket
Granted
                        $msg =~ /User Name:\s*(\S+)\s+.+Service
Name:\s*(\S+)\s+.+Client Address:\s*(\S+)/;
                        #print "DEBUG SGT Granted to $1 for $2 from $3\n";
                        $sgtGranted{$host}{$1}{$2}{$3}++;
                }
                elsif ($detail > 5 && $eventid == 674) { # Ticket Granted
Renewed
                        $msg =~ /User Name:\s*(\S+)\s+.+Service
Name:\s*(\S+)\s+.+Client Address:\s*(\S+)/;
                        #print "DEBUG Ticket Renewal granted to $1 for $2
from $3\n";
                        $renewed{$host}{$1}{$2}{$3}++;
                }
        }

}


# Always print login failures grouped by name and host in that order.
if (keys %loginFail) {
        printLevel2("Windows Failed Logins", \%loginFail);
}

if (keys %krbAuthFail) {
        printLevel3("Kerberos Authentication Failures", \%krbAuthFail);
}

if (keys %lockedOut) {
        printLevel3("Account Locked Out", \%lockedOut);
}

if (keys %ikeSecNegFail) {
        printLevel3("IKE Security Association Negotiation Failed",
\%ikeSecNegFail);
}

if (keys %unmatchedFail) {
        print "\t---- Unmatched Failure Audits ----\n\n";
        foreach $msg (keys %unmatchedFail) {
                print "\t" . $unmatchedFail{$msg} . " Time(s):  $msg\n";
        }
}

# Start printing some other optional data like login successes, account
creation/modification audits, etc.
if ($detail > 3) {
        if (keys %loginSuccess) {
                printLevel2("Windows Successful Logins", \%loginSuccess);
        }

        if ($detail > 5) {
                if (keys %tgtGranted) {
                        printLevel4("TGT Granted", \%tgtGranted);
                }
                if (keys %sgtGranted) {
                        printLevel4("SGT Granted", \%sgtGranted);
                }
                if (keys %renewed) {
                        printLevel4("Ticket Renewed", \%renewed);
                }
        }

        if (keys %auditLogCleared) {
                printLevel3("Audit Log Cleared", \%auditLogCleared);
        }

        if (keys %rightsAdded) {
                printLevel4("User Rights Added", \%rightsAdded);
        }
        if (keys %rightsRemoved) {
                printLevel4("User Rights Removed", \%rightsRemoved);
        }

        if (keys %newDomainTrust) {
                printLevel3("New Domain Trust", \%newDomainTrust);
        }
        if (keys %rmDomainTrust) {
                printLevel3("Domain Trust Removed", \%rmDomainTrust);
        }

        if (keys %auditPolChange) {
                printLevel2("Audit Policy Changed", \%auditPolChange);
        }

        if (keys %newAccount) {
                printLevel3("New Accounts", \%newAccount);
        }
        if (keys %accountTypeChange) {
                printLevel4("Account Type Changed", \%accountTypeChange);
        }
        if (keys %accountEnabled) {
                printLevel3("Account Enabled", \%accountEnabled);
        }
        if (keys %changePasswordAttempt) {
                printLevel3("Change Password Attempt",
\%changePasswordAttempt);
        }
        if (keys %passwordSet) {
                printLevel3("Password Set", \%passwordSet);
        }
        if (keys %accountDeleted) {
                printLevel3("Account Deleted", \%accountDeleted);
        }

        if (keys %groupMemberAdded) {
                printLevel4("Group Member Added", \%groupMemberAdded);
        }
        if (keys %groupMemberRemoved) {
                printLevel4("Group Member Removed", \%groupMemberRemoved);
        }
        if (keys %accountChanged) {
                printLevel3("Account Changed", \%accountChanged);
        }

        if (keys %domainPolicyChanged) {
                printLevel3("Domain Policy Changed", \%domainPolicyChanged);
        }
}



# Prints a hash that's two levels deep in a generic hierarchical manor
sub printLevel2 {
        my $msg = $_[0];
        my %data = %{$_[1]};

        print "\n\t---- $msg ----\n\n";
        foreach $first (sort(keys %data)) {
                $total = 0;
                foreach $second (keys %{$data{$first}}) {
                        $total += $data{$first}{$second};
                }

                print "\t$first  $total Time(s)\n";
                foreach $second (sort(keys %{$data{$first}})) {
                        print  "\t\t" . LookupIP($second) . "  " .
$data{$first}{$second} . " Time(s)\n";
                }
                print "\n";
        }
}

# Prints a hash that's three levels deep in a generic hierarchical manor
sub printLevel3 {
        my $msg = $_[0];
        my %data = %{$_[1]};

        print "\n\t---- $msg ----\n\n";
        foreach $first (sort(keys %data)) {
                $first_total = 0;
                foreach $second (keys %{$data{$first}}) {
                        $second_total{$second} = 0;
                        foreach $third (keys %{$data{$first}{$second}}) {
                                $second_total{$second} +=
$data{$first}{$second}{$third};
                        }
                        $first_total += $second_total{$second};
                }

                print "\t$first:  $first_total Time(s)\n";
                foreach $second (sort(keys %{$data{$first}})) {
                        print "\t\t" . LookupIP($second) .
":  $second_total{$second} Time(s)\n";
                        foreach $third (sort(keys
%{$data{$first}{$second}})) {
                                print "\t\t\t" . LookupIP($third) .
"  $data{$first}{$second}{$third} Time(s)\n";
                        }
                }
                print "\n";
        }
}

# Prints a hash that's four levels deep in a generic hierarchical manor
sub printLevel4 {
        my $msg = $_[0];
        my %data = %{$_[1]};

        print "\n\t---- $msg ----\n\n";
        foreach $first (sort(keys %data)) {
                $first_total = 0;
                foreach $second (keys %{$data{$first}}) {
                        $second_total{$second} = 0;
                        foreach $third (keys %{$data{$first}{$second}}) {
                                $third_total{$second}{$third} = 0;
                                foreach $fourth (keys
%{$data{$first}{$second}{$third}}) {
                                        $third_total{$second}{$third} +=
$data{$first}{$second}{$third}{$fourth};
                                }
                                $second_total{$second} +=
$third_total{$second}{$third};
                        }
                        $first_total += $second_total{$second};
                }

                print "\t$first:  $first_total Time(s)\n";
                foreach $second (sort(keys %{$data{$first}})) {
                        print "\t\t" . LookupIP($second) .
":  $second_total{$second} Time(s)\n";
                        foreach $third (sort(keys
%{$data{$first}{$second}})) {
                                print "\t\t\t" . LookupIP($third) .
":  $third_total{$second}{$third} Time(s)\n";
                                foreach $fourth (sort(keys
%{$data{$first}{$second}{$third}})) {
                                        print "\t\t\t\t" . LookupIP($fourth)
. "  $data{$first}{$second}{$third}{$fourth} Time(s)\n";
                                }
                        }
                }
                print "\n";
        }
}

exit(0);




-- 
Kirk Bauer <[email protected]>
http://linux.kaybee.org | www.autorpm.org | www.logwatch.org

_______________________________________________
Logwatch-Devel mailing list
[email protected]
http://www2.list.logwatch.org:81/mailman/listinfo/logwatch-devel
smime.p7s (application/x-pkcs7-signature, 3.3 KB) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.