0

I am working on writing a script that identifies login attempts that are 5 seconds or less apart, searching for brute force login attempts. So far I have been able to take the log timestamps and convert them to a readable and workable format, by using the script below:

#!/usr/bin/perl
use warnings;
use strict;

open my $IN, '<', 'test.txt' or die $!;  # Open the file.
while (<$IN>) {                          # Process it line by line.
    my $timestamp = (split)[1];          # Get the second column.
    $timestamp =~ tr/://d;               # Remove colons.
    print "$timestamp\n";
}

The output I get looks like

102432
102434
104240

etc.

What I want to do is compare the numbers in the array to see if there is a five-second delay or less between login attempts. Something like:

if ($timestamp + 5 <= 2nd element in array) {
   print "ahhh brute force"
}

The same thing all the way down the array elements until the end.

if (2nd element in array + 5 <= 3rd element in array) {
   print "ahh brute force"
}

etc.

Could someone please point me in the right direction?

Example of input:

2014-08-10      13:20:30        GET     Portal/jsjquery-latest.js  404     -       "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
8
  • can you provide a sample of your input file? Commented Aug 26, 2014 at 15:20
  • 1
    Note that timestamp + 5 is wrong for seconds > 54. Commented Aug 26, 2014 at 15:23
  • Save $timestamp to $timestamp_old and compare these two on each iteration? Commented Aug 26, 2014 at 15:23
  • 1
    I'm afraid you have started from the wrong place: your previous question doesn't get you to a more useful place as you can't just concatenate the time fields and treat them as a number. You will also need the date so that you can subtract times that span a midnight. Presumably the date is in the log too? We can't help you unless you show the format of a log record. Commented Aug 26, 2014 at 15:28
  • 1
    @user3821215 Use a module designed to compare times and dates and you will save yourself a lot of trouble and potential bugs. Commented Aug 26, 2014 at 15:40

1 Answer 1

2

This will do as you ask. It uses Time::Piece, which has been a core module since version 10 of Perl 5, and so shouldn't need installing.

It uses both the date and the time fields from the log file to build Time::Piece objects, which can then be subtracted from one another to calculate the intervals.

The program expects the path to the log file as a parameter on the command line

use strict;
use warnings;
use 5.010;

use Time::Piece;

my $last_login;

while (<>) {
   my @login = split;
   my $login = Time::Piece->strptime("@login[0,1]", '%Y-%m-%d %H:%M:%S');

   if ($last_login) {
      my $interval = $login - $last_login;
      if ($interval <= 5) {
         printf "%s to %s is %d seconds\n", $last_login, $login, $interval;
      }
   }

   $last_login = $login;
}

Update

As @knarf says in a comment, this can be done using a regular expression together with the Time::Local module's timelocal function.

This is a program that does something similar using that technique.

use strict;
use warnings;

use Time::Local 'timelocal';

my $last_login;

while (<>) {
   next unless my @login = / (\d\d\d\d)-(\d\d)-(\d\d) \s+ (\d\d):(\d\d):(\d\d) /x;
   $login[0] -= 1900;
   $login[1] -= 1;
   my $login = timelocal reverse @login;

   if ($last_login) {
      my $interval = $login - $last_login;
      if ($interval <= 5) {
         printf "%s to %s is %d seconds\n", map(scalar localtime $_, $last_login, $login), $interval;
      }
   }

   $last_login = $login;
}
Sign up to request clarification or add additional context in comments.

5 Comments

you can use timelocal from the Time::Local module if Time::Piece is not available. m/^(\d+)-(\d+)-(\d+)\s+(\d+):(\d+):(\d+)/; my $login = timelocal($6, $5, $4, $3, $2, $1);
hey knarf, could you please elaborate more? if you were to use timelocal how would the code change? I understand the fields $6 $5 etc... however im not sure where you would put the REGEX? could just edit borodin's code to show how it would work with timelocal? cheers.
@user3821215: Since you've shown an interest in a solution using Time::Local instead of Time::Piece, I've added to my answer to show you how it could be done; but in my opinion it's not such a clean solution. Do you have a problem with using Time::Piece?
yeah the perl interpreter is old on the server im running it on, and it doesnt like Time:Piece, question though, I ran you above code and the month is off, its saying "Sept 25" should be Aug.25
@user3821215: Okay thanks, I've fixed that. I overlooked that timelocal expects a zero-based month number. Also the year should be relative to 1900 like the localtime return value, but it seems to accept either that or the actual year.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.