【问题标题】:#!/usr/bin/perl, how to match keywords in a string to numbers#!/usr/bin/perl,如何将字符串中的关键字与数字匹配
【发布时间】:2020-11-27 12:34:50
【问题描述】:

背景:我正在使用 Perl 脚本将滥用报告提交到 abuseipdb.com。 该脚本只有一个默认类别(14 端口扫描),但我想为滥用报告提交正确的类别/类别。提交类别由数字完成。可以有多个类别,并用逗号“,”分隔。

分类列表:https://www.abuseipdb.com/categories

脚本来源:https://www.abuseipdb.com/csf,向下滚动大约一半以查看“abuseipdb_report.pl”。

我修改了脚本以扫描日志文件中的关键字,如果找到,则给它一个正确的类别编号。 (缺点:这种方式只能使用1个类别号。)

它工作正常,但远非漂亮。所有这些 if 和 elsif 语句都将花费大量的处理时间。

这是我制作的 sn-ps。 (它正在工作!)

my $cat = '14';
my $logs = $ARGV[6];
if    ($logs =~ m/DOS-PROTECTION/)      {$cat = '4';}
elsif ($logs =~ m/PROTOCOL-ENFORCEMENT/){$cat = '15';}
elsif ($logs =~ m/PROTOCOL-ATTACK/)     {$cat = '15';}
elsif ($logs =~ m/DATA-LEAKAGES/)       {$cat = '16';}
elsif ($logs =~ m/IP-REPUTATION/)       {$cat = '19';}
elsif ($logs =~ m/SCANNER-DETECTION/)   {$cat = '19';}
elsif ($logs =~ m/APPLICATION-ATTACK/)  {$cat = '21';}
elsif ($logs =~ m/METHOD-ENFORCEMENT/)  {$cat = '23';}

my $data = {
    ip => $ARGV[0],
    comment => $comment,
    categories => $cat
};

我尝试过数组和 foreach 循环,但我是 Perl 的新手,无法让它工作。所以我被我的 if elsif 代码卡住了。

所以现在你知道我要完成什么了。

是否有更智能、更快的方法,可能包括多个类别?

$logs 示例:

2020/08/07 06:25:11 [error] 16769#0: *40996 [client 174.xxx.xxx.185] ModSecurity: Access denied with code 406 (phase 2). Matched "Operator `Within' with parameter `.asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .ln (150 characters omitted)' against variable `TX:EXTENSION' (Value: `.bak/' ) [file "/etc/modsecurity.d/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "1015"] [id "920440"] [rev ""] [msg "URL file extension is restricted by policy"] [data ".bak"] [severity "2"] [ver "OWASP_CRS/3.3.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/210/272"] [tag "PCI/6.5.10"] [hostname "46.xxx.xxx.137"] [uri "/wp-config.php.bak"] [unique_id "159678151143.002383"] [ref "o13,4o14,3v5,17o35,5t:urlDecodeUni,t:lower
 case"], client: 174.xxx.xxx.185, server: <removed>, request: "GET /wp-config.php.bak HTTP/1.1", host: "<removed>", referrer: "http://<removed>/"

第二个 $logs 样本:

2020/08/07 06:52:14 [error] 16769#0: *42613 [client 195.xxx.xxx.89] ModSecurity: Access denied with code 406 (phase 2). Matched "Operator `Rx' with parameter `(?i)(?:\x5c|(?:%(?:c(?:0%(?:[2aq]f|5c|9v)|1%(?:[19p]c|8s|af))|2(?:5(?:c(?:0%25af|1%259c)|2f|5c)|%46|f)|(?:(?:f(?:8%8)?0%8|e)0%80%a|bg%q)f|%3(?:2(?:%(?:%6|4)6|F)|5%%63)|u(?:221[56]|002f|EFC8|F025)|1u|5 (400 characters omitted)' against variable `REQUEST_URI_RAW' (Value: `/forum/../forum/index.php' ) [file "/etc/modsecurity.d/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] [line "29"] [id "930100"] [rev ""] [msg "Path Traversal Attack (/../)"] [data "Matched Data: /../ found within REQUEST_URI_RAW: /forum/../forum/index.php"] [severity "2"] [ver "OWASP_CRS/3.3.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-lfi"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/255/153/126"] [hostname "46.xxx.xxx.137"] [uri "/forum/../forum/index.php"] [unique_id "15967831
 3492.204063"] [ref "o6,4v4,25"], client: 195.xxx.xxx.89, server: <removed>, request: "GET /forum/../forum/index.php HTTP/1.1", host: "<removed>"

现在我正在匹配来自 modsecurity 的 .conf 文件。但我可能会更好地检查“标签”cmets。


解决方案
借助此处给出的答案,我得到了适合我的解决方案。我唯一要做的就是微调数组。

my $logs = "attack-protocol attack-reputation-scanner attack PROTOCOL-ENFORCEMENT   ";
my %categories = (
    'DOS-PROTECTION'        =>  4,
    'PROTOCOL-ENFORCEMENT'  => 15,
    'PROTOCOL-ATTACK'       => 15,
    'DATA-LEAKAGES'         => 16,
    'IP-REPUTATION'         => 19,
    'SCANNER-DETECTION'     => 19,
    'APPLICATION-ATTACK'    => 21,
    'METHOD-ENFORCEMENT'    => 23,
    'attack-lfi'            => 10,
    'attack-protocol'       => 11,
    'attack-reputation-scanner' => 12,
    'attack'                => 15,
);

my @cats = ();
for (keys %categories) {
  if ($logs =~ /$_/) {
    push @cats, $categories{$_};
  }
}

my %hash = map { $_ => 1 } @cats;
@cats = keys %hash;

print categories => join ',', @cats,;

【问题讨论】:

  • 您能否展示一下 $logs 中的内容示例?
  • $logs 示例已添加到问题中。我不能在这里提交。字符太多。
  • 添加了第二个样本。

标签: arrays regex perl


【解决方案1】:

执行这些操作的常用方法是将您要查找的所有标记组合在一起,形成一个可以匹配一次的替换。例如

my %keys = (
    'DOS-PROTECTION', 4,
    'PROTOCOL-ENFORCEMENT', 15,
    # ....
);
my $pattern = join '|', map quotemeta, sort keys %keys;
$pattern = qr/($pattern)/;

while (<DATA>) {
    my $cat = 14;
    $cat = $keys{$1} if /$pattern/;
    print "[$cat]\n";
}

__DATA__
blah blah DOS-PROTECTION blah blah
blah blah PROTOCOL-ENFORCEMENT blah blah
blah blah
blah blah

【讨论】:

  • 您的代码尚未取得任何成功。我需要用 $logs 替换 吗?
  • 我的示例代码只是一个演示 - 从文件末尾读取日志行。用你得到的日志文件行替换while循环。如果该行在 $logs 中,则将条件更改为 ... if $logs =~ /$pattern/。如果 $logs 包含多行,您将不得不做一些不同的事情。
【解决方案2】:

一个明显的改进是将您的类别存储在一个数组中。这样,您可以提交多个类别:

my @cats = (14);

my $logs = $ARGV[6];
if    ($logs =~ m/DOS-PROTECTION/)          { push @cats, 4;}
elsif ($logs =~ m/PROTOCOL-ENFORCEMENT/)    { push @cats, 15;}
# etc...

my $data = {
  ip => $ARGV[0],
  comment => $comment,
  categories => join ',', @cats,
};

我还会考虑一种数据驱动的方法,其中您匹配的字符串与相关类别一起存储在哈希中。

my %categories = (
  'DOS-PROTECTION'       =>  4,
  'PROTOCOL-ENFORCEMENT' => 15,
  # etc...
);

然后您可以使用循环进行检查:

my @cats = (14);

my $logs = $ARGV[6];

for (keys %categories) {
  if ($logs =~ /$_/) {
    push @cats, $categories{$_};
  }
}

【讨论】:

  • 我已经让你的代码工作了!我采用了数据驱动的方法。坦克!是否有删除重复类别的选项?不幸的是,接收方没有过滤掉重复的类别。
  • 找到了删除重复项的方法:```` my %hash = map { $_ => 1 } @cats; @cats = 键 %hash; ```` 来源:stackoverflow.com/a/12921325
  • @karel 跳过数组并将分类直接存储在集合中作为哈希的键更简单。 $cats{ $categories{$1} } = 1 用于存储,keys %cats 用于获取唯一类别。
猜你喜欢
  • 1970-01-01
  • 2021-12-28
  • 2021-04-28
  • 2022-11-18
  • 2014-10-12
  • 1970-01-01
  • 2012-12-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多