天天看点

Perl与网络监控

Perl与网络监控

  1. 发现主机
  • Net::Ping

    可以发送ICMP,TCP,UDP的Ping包。但该模块需要管理员权限。

use Net::Ping;
use Net::Netmask;

my $ping=Net::Ping->new('icmp'); #需要root权限

#输入掩码
die $Net::Netmask::error unless my $netblock=new2 Net::Netmask($ARGV[0]); #new2方法调用失败返回undef, 而new则返回空对象。
my $blocksize=$netblock->size()-1;

my (@addrs);
for(my $i=1;$i<=$blocksize;$i++){
    my $addr=$netblock-nth($i);
    push(@addrs, $addr) if $ping->ping($addr, 1);
}
print "Found\n", join("\n", @addrs), "\n" if scalar @addrs;      
  • Net::Ping::External

    可以不依赖管理员权限。它帮助权限不足的Perl脚本调用操作系统内置的ping可执行程序,而该ping程序已经为普通用户设置了合适的执行权限,也能免于安全检查。它让Perl脚本可以不考虑不同平台的输入输出差异。

use Net::Ping::External qw(ping);

# Ping a single host
my $alive = ping(host => "127.0.0.1");
print "127.0.0.1 is online" if $alive;

# Or a list of hosts
my @hosts = qw(127.0.0.1 127.0.0.2 127.0.0.3 127.0.0.4);
my $num_alive = 0;
foreach (@hosts) {
  $alive = ping(hostname => $_, timeout => 5);
  print "$_ is alive!\n" if $alive;
  $num_alive++;
}
print "$num_alive hosts are alive.\n";

# Using all the fancy options:
ping(hostname => "127.0.0.1", count => 5, size => 1024, timeout => 3);      
  • 构建ARP报文
nemesis arp -v -S 192.168.13.13 -D 192.168.13.18      

ARP报文结构

Perl与网络监控

构造ARP报文还可以使用如下模块

Net::Packet

Net::Pcap

当然也可以使用如下模块来完成arp的扫描

Net::Arping

use Net::Arping;

my $arping=Net::Arping->new(); #如果收到ARP响应,arping()会返回其中的MAC地址
my $return=$arping->arping($ARGV[0]);
print "$ARGV[0]" .
    ($return)? "($return) is up\n" : "is down\n";      
  1. 嗅探ARP流量
use Net::PcapUtils;
use NetPacket::Ethernet;
use NetPacket::ARP;

my $filter='arp';
my $dev='eth1';
my %addresses=();

die 'Unable to perform capture: '.Net::Pcap::geterr($dev)."\n" 
    if(Net::PcapUtils::loop(\&CollectPackets,
                            FILTER=>$filter,
                            DEV=>$dev,
                            NUMPACKETS=>100, #监听100个包
        )
    );

print join("\n", keys %addresses), "\n";

sub{
    my ($arg, $hdr, $pkt)=@_;
    #将IP地址从十六进制形式转换为点分十进制形式
    my $ip_add=join(
        '.',
        unpack(
            'C*',
            pack('H*',
                NetPacket::ARP->decode(NetPacket::Ethernet::strip($pkt))
                ->{'spa'}
            )
        )
    );
    $addresses{$ip_addr}++;
}      
  1. 嗅探DHCP流量
use Net::PcapUtils;
use NetPacket::Ethernet;
use NetPacket::IP;

my $filter='dst port 68'; #DHCP客户端侦听端口
my $dev='eth1';
my %addresses=();

die 'Unable to perform capture: '.Net::Pcap::geterr($dev)."\n" 
    if(Net::PcapUtils::loop(\&CollectPackets,
                            FILTER=>$filter,
                            DEV=>$dev,
                            NUMPACKETS=>100, #监听100个包
        )
    );
print join("\n", keys %addresses), "\n";

sub{
    my ($arg, $hdr, $pkt)=@_;
    #将IP地址从十六进制形式转换为点分十进制形式
    my $ip_add=NetPacket::IP->decode(NetPacket::Ethernet::strip($pkt))->{'src_ip'}; #获取DHCP Server的IP地址
    $addresses{$ip_addr}++;
}      
  1. 扫描端口

使用的模块

Nmap::Scanner 调用nmap的模块

Nmap::Parser 分析XML模式的nmap输出

Nmap::Scanner的批处理模式

use Nmap::Scanner;

my $nscan=new Nmap::Scanner;
#nmap命令的位置可以给绝对路径,也可以省略(让perl从$PATH环境变量中查找)
$nscan->nmap_location('/usr/local/bin/nmap');

#开始扫描
my $nres=$nscan->scan('-p 80 192.168.10.0/24');
my $nhosts=$nres->get_host_list();

#遍历找到的主机
while(my $host=$nhosts->get_next()){
    print $host->hostname()."\n" if $host->get_port("tcp", 80)->state() eq 'open';
}      

Nmap::Scanner的事件驱动模式

use Nmap::Scanner;

my $nscan=new Nmap::Scanner;
$nscan->nmap_location('/usr/local/bin/nmap');

#每发现一个端口就运行&printIfOpen
$nscan->register_port_found_event(\&PrintIfOpen);

my $nres=$nscan->scan('-p 80 118.37.13.0/24');

sub{
    #定义回调函数
    my ($self, $host, $port)=@_; #扫描对象,主机对象,端口对象
    print $host->hostname()."\n" if $port->state() eq 'open';
}      

使用Nmap::Scanner模块可以识别操作系统和版本。

...
#测试打开的端口是否可以提供服务
my $nres=$nscan->scan('-p 80 -sV 192.168.10.0/24'); #加上-O参数可以识别操作系统
...
sub{
    #定义回调函数
    my ($self, $host, $port)=@_; #扫描对象,主机对象,端口对象
    print $host->get_port('tcp', 80)->sevice->extrainfo().'\n';
    print $host->get_port('tcp', 80)->sevice->product().'\n';
    print $host->get_port('tcp', 80)->sevice->version().'\n';
}      
  1. 文本显示

常用模块

Text::Wrap

Text::Beautify

Text::Autoformat

  • 使用Text::Autoformat格式化文本显示
use Text::Autoformat;
my $a='......
......
......
';
print autoformat($a, {all=>1});      
  1. 文本表格

涉及的模块

Array::PrintCols

Text::TabularDisplay

Text::FormatTable

Text::ASCIITable

Data::ShowTable

use Text::FormatTable;
my %results=(
    'drummoud'=>{
        status=>'passed',
        owner=>'stracy'
    },
    'brady'=>{
        status=>'passed',
        owner=>'vivid'        
    },
    'hornbeck'=>{
        status=>'passed',
        owner=>'yaboo'                
    }
);
my $table=Text::FormatTable->new('|l|l|l|');
$table->rule('-');
$table->head(qw(Host Status Owner));
$table->rule('-');
foreach (sort keys %results){
    $table->row($_,$results{$_}{status}, $results{$_}{owner});
}
$table->rule('-');
print $table->render();      
  1. 文本进度条
use Text::BarGraph;

my %hoststats=(
            'cbd1'=>10,
            'wcc'=>20,
            'etl'=>30,
            'ppe'=>100,
            'llade'=>55
            );
            
my $g=Text::BarGraph->new();

$g->{columns}=70; #设置列宽
$g->{num}=1; #在条形边上显示数值

print $g->graph(\%hoststats);      
  1. CSV的处理
  1. 获取IP地址的物理位置