使用 perl 计算日志文件中变量组合的数量
Count the number of variable combinations in a logfile using perl
我有这个日志文件
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 语句无法正常工作。有帮助吗?
这是获得预期输出的基本方法。关于上下文(目的)的问题仍然存在。
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
这会打印
Port,Status,Occurences
64400,failed,2
64400,failed,1
我拿整个user1/test123
(等等)来识别用户。这可以根据需要在正则表达式中更改。
请注意,这将不允许您以非常不同的方式查询或组织数据,它主要提取所需输出所需的内容。如果需要解释,请告诉我。
上面使用的嵌套哈希的介绍性解释
首先,我强烈建议您好好阅读一些可用的资料。
Perl 的标准教程肯定是一个好的开始
参考文献,以及各种食谱
在 Perl data structures.
用于收集数据的散列有键是端口号,每个键都有
其值是一个 哈希引用 (或者更确切地说,一个 匿名哈希 )。这些中的每一个
散列具有作为用户的键,其值再次具有散列引用。
这些键是状态的可能值,因此有两个键(失败
并成功)。它们的值是频率。这种'nesting'是复合体
数据结构。还有一件很重要的事。第一时间声明
$rept{$port}{$usr}{$status}++
可见整个层次结构已创建。所以关键
$port
不需要预先存在。重要的是,这个自动激活
即使仅查询结构的值也会发生(除非它实际存在
已经)。
第一次迭代后,哈希为
%rept = { '64400' => { 'user1/test123' => { 'failed' => 1 } } }
在第二次迭代中看到相同的端口但是一个新用户,因此新数据被添加到二级匿名散列中。创建新用户的密钥,其值为(新)匿名散列,status => count
。整个哈希是:
%rept = {
'64400' => {
'user1/test123' => { 'failed' => 1 },
'user1/test1234' => { 'failed' => 1 },
}
}
在下一次迭代中看到相同的端口和一个已经存在的用户,并且
因为它发生在状态(失败)也存在。因此,计数
状态递增。
可以很容易地看到整个结构,例如,
Data::Dumper 包。
上面代码中注释掉的行将产生
$VAR1 = {
'64400' => {
'user1/test123' => {
'failed' => 2
},
'user1/test1234' => {
'failed' => 1
}
}
};
随着我们继续处理行,根据需要添加新键(端口、用户、状态),整个层次结构向下计数(第一次为 1),或者,如果遇到现有的,则其计数为递增。例如,可以如代码中所示遍历和使用生成的数据结构。另请参阅大量文档以获取更多相关信息。
我有这个日志文件
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 语句无法正常工作。有帮助吗?
这是获得预期输出的基本方法。关于上下文(目的)的问题仍然存在。
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
这会打印
Port,Status,Occurences 64400,failed,2 64400,failed,1
我拿整个user1/test123
(等等)来识别用户。这可以根据需要在正则表达式中更改。
请注意,这将不允许您以非常不同的方式查询或组织数据,它主要提取所需输出所需的内容。如果需要解释,请告诉我。
上面使用的嵌套哈希的介绍性解释
首先,我强烈建议您好好阅读一些可用的资料。 Perl 的标准教程肯定是一个好的开始 参考文献,以及各种食谱 在 Perl data structures.
用于收集数据的散列有键是端口号,每个键都有
其值是一个 哈希引用 (或者更确切地说,一个 匿名哈希 )。这些中的每一个
散列具有作为用户的键,其值再次具有散列引用。
这些键是状态的可能值,因此有两个键(失败
并成功)。它们的值是频率。这种'nesting'是复合体
数据结构。还有一件很重要的事。第一时间声明
$rept{$port}{$usr}{$status}++
可见整个层次结构已创建。所以关键
$port
不需要预先存在。重要的是,这个自动激活
即使仅查询结构的值也会发生(除非它实际存在
已经)。
第一次迭代后,哈希为
%rept = { '64400' => { 'user1/test123' => { 'failed' => 1 } } }
在第二次迭代中看到相同的端口但是一个新用户,因此新数据被添加到二级匿名散列中。创建新用户的密钥,其值为(新)匿名散列,status => count
。整个哈希是:
%rept = {
'64400' => {
'user1/test123' => { 'failed' => 1 },
'user1/test1234' => { 'failed' => 1 },
}
}
在下一次迭代中看到相同的端口和一个已经存在的用户,并且 因为它发生在状态(失败)也存在。因此,计数 状态递增。
可以很容易地看到整个结构,例如, Data::Dumper 包。 上面代码中注释掉的行将产生
$VAR1 = { '64400' => { 'user1/test123' => { 'failed' => 2 }, 'user1/test1234' => { 'failed' => 1 } } };
随着我们继续处理行,根据需要添加新键(端口、用户、状态),整个层次结构向下计数(第一次为 1),或者,如果遇到现有的,则其计数为递增。例如,可以如代码中所示遍历和使用生成的数据结构。另请参阅大量文档以获取更多相关信息。