【问题标题】:Count the number of variable combinations in a logfile using perl使用 perl 计算日志文件中变量组合的数量
【发布时间】:2016-05-01 09:11:59
【问题描述】:

我有这个日志文件

 New connection: 141.8.83.213:64400 (172.17.0.6:2222) [session: e696835c]
    2016-04-29 21:13:59+0000 [SSHService ssh-userauth on HoneyPotTransport,3,141.8.83.213] login attempt [user1/test123] failed
    2016-04-29 21:14:10+0000 [SSHService ssh-userauth on HoneyPotTransport,3,141.8.83.213] login attempt [user1/test1234] failed
    2016-04-29 21:14:13+0000 [SSHService ssh-userauth on HoneyPotTransport,3,141.8.83.213] login attempt [user1/test123] failed

我想将这样的结果输出到文件:

Port,Status,Occurrences
64400,failed,2
64400,failed,1

“Occurrences”变量将表示已记录在文件中的登录详细信息[用户名和密码]组合的次数。 User1 test123 可以看到从同一个 IP 记录了两次。我怎样才能做到这一点?我现在有两个 while 循环,并且在第一个 while 循环中调用了一个子例程,如下所示:

子程序

sub counter(){

        $result = 0;
        #open(FILE2, $cowrie) or die "Can't open '$cowrie': $!";
        while(my $otherlines = <LOG2>){

                if($otherlines =~ /login attempt/){
                        ($user, $password) = (split /[\s:\[\]\/]+/, $otherlines)[-3,-2];
                        if($_[1] =~ /$user/ && $_[2] =~ /$password/){
                                $result++;
                        }#if ip matches i think i have to do this with split

                        #print "TEST\n";
                }
        #print "Combo $_[0] and $_[1]\n";

        }
        #print "$result";
        return $result;
}

主要方法

sub cowrieExtractor(){

        open(FILE2, $cowrie) or die "Can't open '$cowrie': $!";

        open(LOG2, $path2) or die "Can't open '$path2': $!";

        $seperator = chr(42);
        #To output user and password of login attempt, set $ip variable to the contents of array at that x position of new
        #connection to match the ip of the login attempt
        print FILE2 "SourcePort"."$seperator".
        "Status"."$seperator"."Occurences"."$seperator"."Malicious"."\n";

        $ip = "";
        $port = "";
        $usr = "";
        $pass = "";
        $status = "";
        $frequency = 0;

        #Given this is a user/pass attempt honeypot logger, I will use a wide character to reduce the possibility of stopping
        #the WEKA CSV loader from functioning by using smileyface as seperators.


        while(my $lines = <LOG2>){

                if($lines =~ /New connection/){

                ($ip, $port) = (split /[\[\]\s:()]+/, $lines)[7,8];

                }
                if($lines =~ /login attempt/){#and the ip of the new connection
if($lines =~ /$ip/){
                ($usr, $pass, $status) = (split /[\s:\[\]\/]+/, $lines)[-3,-2,-1];

                        $frequency = counter($ip, $usr, $pass);

                        #print $frequency;
                        if($ip && $port && $usr && $pass && $status ne ""){
                                print FILE2 join "$seperator",($port, $status, $frequency, $end);
                                print FILE2 "\n";
                        }
                }


                }
        }


}

现在在输出中Occurrences 下的输出中,我得到一个0,当我测试它似乎来自我在子例程中初始化变量$result 的内容。即0;这意味着子例程中的 if 语句无法正常工作。有什么帮助吗?

【问题讨论】:

  • 你永远不应该在 Perl 子例程中使用原型。他们不会做你认为他们会做的事。只是sub counter { ... }sub cowrieExtractor { ... } 是正确的
  • “尽可能不涉及散列” 散列正是解决此问题的正确工具。为什么要避开它们?
  • 我不禁要问:为什么“不涉及哈希”?这意味着什么——一个根本不使用哈希数据类型的解决方案? (您的具体要求是什么?)
  • 我很困惑您的输出示例显示 statusport 字段但没有用户信息,但您说要对信息进行分组仅由用户。这意味着每个计数都会混合使用状态和端口,并且无法像这样汇总数据
  • 很抱歉没有涉及哈希部分。我刚刚做了一些研究,哈希非常适合这个我只是不知道如何很好地使用它们。

标签: perl logging pattern-matching subroutine


【解决方案1】:

这是获得预期输出的基本方法。关于上下文(目的)的问题仍然存在。

use warnings;
use strict;

my $file = 'logfile.txt';
open my $fh_in, '<', $file;

# Assemble results for required output in data structure:
# %rept = { $port => { $usr => { $status => $freq } };

my %rept;
my ($ip, $port);

while (my $line = <$fh_in>) 
{
    if ($line =~ /New connection/) {
        ($ip, $port) = $line =~ /New connection:\s+([^:]+):(\d+)/;
        next;
    }   

    my ($usr, $status) =  $line =~ m/login\ attempt \s+ \[ ( [^\]]+ ) \] \s+ (\w+)/x;
    if ($usr and $status) {
        $rept{$port}{$usr}{$status}++;
    }   
    else { warn "Line with an unexpected format:\n$line" }
}

# use Data::Dumper;
# print Dumper \%rept;

print "Port,Status,Occurences\n";
foreach my $port (sort keys %rept) {
    foreach my $usr (sort keys %{$rept{$port}}) {
        foreach my $stat ( sort keys %{$rept{$port}{$usr}} ) { 
            print "$port,$stat,$rept{$port}{$usr}{$stat}\n"; 
        }   
    }   

}

将您的输入复制到文件logfile.txt 中会打印出来

端口、状态、事件 64400,失败,2 64400,失败,1

我使用整个user1/test123(等)来识别用户。这可以根据需要在正则表达式中更改。 请注意,这不允许您以非常不同的方式查询或组织数据,它主要提取所需输出所需的内容。如果需要解释,请告诉我。


上面使用的嵌套哈希的介绍性解释

首先,我强烈建议您好好阅读一些可用的材料。 一个好的开始肯定是Perl references 上的标准教程,以及各种食谱 在Perl data structures.

用于收集数据的散列具有作为端口号的键,每个键都有 它的值是一个散列引用(或者,更确切地说,一个匿名散列)。这些中的每一个 hashes 的键是用户,它们的值再次具有散列引用。 这些的键是状态的可能值,所以有两个键(失败 并成功)。它们的值是频率。这种“嵌套”是一个复杂的 数据结构。还有一件很重要的事情。第一次声明 可以看到$rept{$port}{$usr}{$status}++ 创建了整个层次结构。所以关键 $port 不需要事先存在。重要的是,这个自动复活 即使仅查询结构的值也会发生(除非它实际存在 已经)。

第一次迭代后,哈希为

%rept = { '64400' => { 'user1/test123' => { 'failed' => 1 } } }

在第二次迭代中,看到的是相同的端口但是一个新用户,因此新数据被添加到第二级匿名哈希中。创建新用户的密钥,其值为(新)匿名哈希,status =&gt; count。整个哈希是:

%rept = { 
    '64400' => { 
        'user1/test123'  => { 'failed' => 1 },
        'user1/test1234' => { 'failed' => 1 },
    } 
}

在下一次迭代中,会看到相同的端口和已经存在的用户之一,并且 因为它也存在状态(失败)。因此计数 状态递增。

整个结构可以很容易地看到,例如, Data::Dumper 包。 上面代码中被注释掉的行会产生

$VAR1 = { '64400' => { 'user1/test123' => { '失败' => 2 }, 'user1/test1234' => { '失败' => 1 } } };

随着我们不断处理行,新的键会根据需要添加(端口、用户、状态),完整的层次结构一直到计数(第一次为 1),或者,如果遇到现有的,它的计数会增加。例如,生成的数据结构可以像代码中看到的那样被遍历和使用。另请参阅丰富的文档以了解更多信息。

【讨论】:

  • 这非常有效,谢谢。如果我还想根据 IP X.X.X.X 使用相同的 pass/usr 尝试组合的次数来增加出现次数怎么办?因此,如果有多个端口使用相同的组合或 IP 使用相同的组合,它会像 || 语句以某种方式递增?
  • 另外,my ($usr, $status) = $line =~ m/login\ attempt \s+ \[ ( [^\]]+ ) \] \s+ (\w+)/x; 是如何工作的,以便我也可以提取 IP 并在递增之前设置or 条件?
  • @firepro20 我会尽快处理这个问题,并添加一个解释。但是,鉴于您的下一篇文章,这可能会立即有所帮助。 $rept{$port}{$usr}{$stat}(从打印的最后一行开始)的含义如下:在哈希 %rept、端口号 $port 和用户 $usr 和状态 $stat(失败或成功)中,频率精确那,$rept{$port}{$usr}{$stat}。所以这是用户$usr 在端口$port 的“失败”或“成功”的频率。然后打印通过所有可能性,为每个用户在每个端口提供每个状态的频率。这有帮助吗?
  • @firepro20 我已经添加了各种解释。我明天会编辑,因为我确信它可以改进。但是从更好的来源阅读这个,例如第一个链接。如果您继续使用 Perl,它将很容易获得回报。请告诉我进展如何。
  • 所以按照你的解释,我需要创建一个新的哈希,比如 %test 并去哪里有这行代码my ($usr, $status) = $line =~ m/login\ attempt \s+ \[ ( [^\]]+ ) \] \s+ (\w+)/x; (p.s我怎样才能从那个匹配的正则表达式中获取 IP?)提取登录尝试行中的 IP 并说if ($ip){%test($ip)++} 然后转到打印部分并在所有foreach 之后执行以下foreach my $ip(sort keys %($test($ip)))print "$port,$stat,$rept{$port}{$usr}{$stat}, $test{$ip}\n"; 正确吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多