我有一个巨大的scan.gnmap
文件:
Host: 1.1.1.1 () Status: Up
Host: 1.1.1.1 () Ports: 80/open/tcp//http//nginx/, 443/open/tcp//ssl|http//nginx/ Ignored State: filtered (4998)
Host: 2.2.2.2 (foo.com) Status: Up
Host: 2.2.2.2 (foo.com) Ports: 80/open/tcp//http//awselb|2.0/, 443/open/tcp//ssl|http//Apache httpd 2.4.41 (() PHP|5.3.29)/ Ignored State: filtered (4998)
Host: 3.3.3.3 (bar.com) Status: Up
Host: 3.3.3.3 (bar.com) Ports: 25/open/tcp//smtp?/// Ignored State: filtered (4999)
Host: 4.4.4.4 () Status: Up
Host: 4.4.4.4 () Ports: 80/open/tcp//http//Microsoft-Azure-Application-Gateway|v2/, 443/open/tcp//ssl|https//Microsoft-Azure-Application-Gateway|v2/ Ignored State: filtered (4998)
Host: 5.5.5.5 (foobar.com) Status: Up
Host: 5.5.5.5 (foobar.com) Ports: 80/open/tcp//http?///, 443/open/tcp//ssl|https?/// Ignored State: filtered (4998)
Host: 6.6.6.6 () Status: Up
Host: 6.6.6.6 () Ports: 80/open/tcp//http//Microsoft IIS httpd 10.0/, 443/open/tcp//ssl|http//Microsoft IIS httpd 10.0/, 454/open/tcp//ssl|upnp//Microsoft IIS httpd/, 1221/open/tcp//http//Microsoft HTTPAPI httpd 2.0 (SSDP|UPnP)/, 4022/open/tcp//dnox?///, 4024/open/tcp//tnp1-port?///, 7654/open/tcp//unknown/// Ignored State: filtered (4993)
我试图在附加端口号的同时提取所有 HTTP 服务(包括端口 1221、454 和 443 上的服务),但我的尝试失败了:
$ awk '/open/{print $2" "$5}' scan.gnmap | sed -e 's/\// /g' | awk '/http/{print $1":"$2}'
1.1.1.1:80
2.2.2.2:80
4.4.4.4:80
5.5.5.5:80
6.6.6.6:80
提取所有 HTTP 主机:端口组合的最简单方法是什么?
答案1
这是对您的需求的一种可能的解释,使用任何 POSIX awk:
$ cat tst.awk
BEGIN { OFS=":" }
{ ip = $2 }
sub(/^([^[:space:]]+[[:space:]]+){3}Ports:[[:space:]]+/,"") {
n = split($0,f,/\/[^,]+(,[[:space:]]*|[[:space:]]*$)/)
for (i=1; i<n; i++) {
port = f[i]
if ( !seen[ip,port]++ ) {
print ip, port
}
}
}
$ awk -f tst.awk file
1.1.1.1:80
1.1.1.1:443
2.2.2.2:80
2.2.2.2:443
3.3.3.3:25
4.4.4.4:80
4.4.4.4:443
5.5.5.5:80
5.5.5.5:443
6.6.6.6:80
6.6.6.6:443
6.6.6.6:454
6.6.6.6:1221
6.6.6.6:4022
6.6.6.6:4024
6.6.6.6:7654
如果您的 awk 不支持字符类,因此不符合 POSIX 标准,只需将 every更改[[:space:]]
为[ \t]
和。[^[:space:]]
[^ \t]
答案2
#!/usr/bin/perl
use strict;
while(<>) {
next unless m/^Host: ([0-9.]+) .* Ports: (.*)(?:\s+Ignored.*)?/;
# $1 and $2 are the values from the capture groups in the previous regex
my ($ip, $ports) = ($1, $2);
# split $ports into array @ports
my @ports = split /,\s+/, $ports;
# iterate over the array and output the IP and port number only when http appears
foreach (@ports) {
next unless s=^(\d+)\/.*http.*=$1=;
printf "%s: %s\n", $ip, $_;
};
}
另存为,例如,grep-http-ports.pl
并使用chmod +x grep-http-ports.pl
.运行如下:
$ ./grep-http-ports.pl scan.gnmap
1.1.1.1: 80
1.1.1.1: 443
2.2.2.2: 80
2.2.2.2: 443
4.4.4.4: 80
4.4.4.4: 443
5.5.5.5: 80
5.5.5.5: 443
6.6.6.6: 80
6.6.6.6: 443
6.6.6.6: 454
6.6.6.6: 1221
冒号后面的空格:
, 是可选的。在我看来,它们使它更加“人类可读”。但是,如果您不喜欢它们或者输出打算用另一个脚本进一步处理,只需编辑printf
格式字符串即可删除它们。
如果您还想提取主机名,这很容易完成:
#!/usr/bin/perl
use strict;
while(<>) {
next unless m/^Host: ([0-9.]+) \(([^)]*)\).* Ports: (.*)(?:\s+Ignored.*)?/;
my ($ip, $host, $ports) = ($1, $2, $3);
my @ports = split /,\s+/, $ports;
foreach (@ports) {
next unless s=^(\d+)\/.*http.*=$1=;
printf "%s:%s:%s\n", $ip, $host, $_;
};
}
1.1.1.1::80
1.1.1.1::443
2.2.2.2:foo.com:80
2.2.2.2:foo.com:443
4.4.4.4::80
4.4.4.4::443
5.5.5.5:foobar.com:80
5.5.5.5:foobar.com:443
6.6.6.6::80
6.6.6.6::443
6.6.6.6::454
6.6.6.6::1221
或者每个 IP 地址和端口号各占一行,并用逗号和空格分隔:
#!/usr/bin/perl
use strict;
while(<>) {
next unless m/^Host: ([0-9.]+) .* Ports: (.*)(?:\s+Ignored.*)?/;
my ($ip, $ports) = ($1, $2);
next unless $ports =~ m/http/;
my @ports = split /,\s+/, $ports;
my @http = ();
foreach (@ports) {
next unless s=(\d+)\/.*http.*=$1=;
push @http, $_;
};
printf "%s: %s\n", $ip, join(", ", @http);
}
$ ./grep-http-ports2.pl scan.gnmap
1.1.1.1: 80, 443
2.2.2.2: 80, 443
4.4.4.4: 80, 443
5.5.5.5: 80, 443
6.6.6.6: 80, 443, 454, 1221
同样,冒号和逗号后面的空格是可选的。根据需要编辑printf
格式字符串和字符串。join