# 引用所有相关的模块 # 定义日志文件名 # 以后台进程方式运行 sub daemon { # 抓包循环 # 进入工作目录 # 设置信号处理函数,因为程序运行于后台,退出时需要利用信号处理函数做些清理工作 # 进入抓包回调函数 sub sniffit { # TCP协议 # 检查来自SMB客户端的包 } elsif ($tcp->{dest_port} == 21) { } else {} sub SmbClientCheck { # 调用SMB解码模块解码 # 如果解码成功 # 如果SMB命令是Session Setup AndX sub FtpClientCheck { # 调用FTP解码模块解码 # 如果解码成功 # 遍历从数据包里解码出来的FTP命令及其参数 # 记录攻击告警 my $nowtime = localtime; # 记录监控信息 my $nowtime = localtime; # INT信号处理例程 CleanUp (); # TERM信号处理例程 CleanUp (); # 清理,主要工作是关闭文件句柄
用PERL实现一个简单的NIDS
perl-ids.pl
实现抓包及检测分析的主程序。
-------- 8< --------------
#!/usr/bin/perl
#
# Comments/suggestions to stardust at xfocus dot org
#
#
# $Id: perl-ids.pl,v 1.16 2004/03/04 21:51:12 stardust Exp $
#
use Net::PcapUtils;
use NetPacket::Ethe.net qw(:strip);
use NetPacket::TCP;
use NetPacket::IP qw(:protos);
use NetPacket::SMB;
use NetPacket::FTP;
$workingdir = "./";
$attacklog = "attack.log";
$monitorlog = "monitor.log";
daemon ();
unless (fork) {
SniffLoop ();
exit 0;
}
exit 1;
}
sub SniffLoop {
chdir ("$workingdir");
# 打开日志文件
open (ATTACKLOG,">> $attacklog");
open (MONITORLOG,">> $monitorlog");
# 设置文件读写为非缓冲模式
select(ATTACKLOG); $ ++; select(MONITORLOG); $ ++; select(STDOUT); $ ++;
$SIG{"INT"} = 'HandleINT';
$SIG{"TERM"} = 'HandleTERM';
Net::PcapUtils::loop(\&sniffit, SNAPLEN => 1800, Promisc => 1, FILTER => 'tcp or udp', DEV => 'eth0');
}
my ($args,$header,$packet) = @_;
# 解码IP包
$ip = NetPacket::IP->decode(eth_strip($packet));
if ($ip->{proto} == IP_PROTO_TCP) {
# 解码TCP包
$tcp = NetPacket::TCP->decode($ip->{data});
if (($tcp->{dest_port} == 139) ($tcp->{dest_port} == 445)) {
# 如果目的端口是139或445,认为是SMB协议包,做相应的检查
SmbClientCheck ($ip->{src_ip},$tcp->{src_port},$ip->{dest_ip},$tcp->{dest_port},$tcp->{data});
# 如果目的端口是21,认为是FTP协议,做相应的检查
FtpClientCheck ($ip->{src_ip},$tcp->{src_port},$ip->{dest_ip},$tcp->{dest_port},$tcp->{data});
# UDP协议
} elsif ($ip->{proto} == IP_PROTO_UDP) {
} else {}
}
my ($src_ip,$src_port,$dest_ip,$dst_port,$data) = @_;
$smb = NetPacket::SMB->decode($data);
if ($smb->{valid}) {
# 示例检测新近公布eeye的那个ASN.1解码错误导致的堆破坏漏洞
# BID:9633,9635 CVEID:CAN-2003-0818 NSFOCUSID:6000
if ($smb->{cmd} == 0x73) {
# 如果设置了Extended Security Negotiation位,表示有包里有Security Blob
if ($smb->{flags2} & F2_EXTSECURINEG) {
# 用正则表达式匹配通常会在攻击包里出现的OID及引发错误的畸形数据串
# 由于不是从原理上检测加之ASN.1编码的灵活性,这样的检测会导致漏报
if (($smb->{bytecount} > 0) && ($smb->{bytes} =~ m/\x06\x06\x2b\x06\x01\x05\x05\x02.*[\xa1\x05\x23\x03\x03\x01\x07 \x84\xff\xff\xff]/)) {
# 记入日志文件
LogAlert ($src_ip,$src_port,$dest_ip,$dst_port,"ASN.1 malform encode attack!");
}
}
}
}
}
my ($src_ip,$src_port,$dest_ip,$dst_port,$data) = @_;
$ftp = NetPacket::FTP->decode($data);
if ($ftp->{valid}) {
# 示例检测新近公布的Serv-U < 5.0.0.4版FTP服务器MDTM命令溢出攻击
# BID:9751 NSFOCUSID:6078
for (my $i = 1;$i <= $ftp->{cmdcount};$i++) {
my $cmd = "cmd"."$i";
my $para = "para"."$i";
# 如果FTP命令是MDTM
if (uc($ftp->{$cmd}) eq "MDTM") {
# 用正则表达式匹配引发溢出的参数串,这里体现了正则
# 表达式的强大,用此匹配可以从原理上检测到畸形参数串
if ($ftp->{$para} =~ m/\d{14}[+ -]\S{5,}\s+\S{1,}/) {
LogAlert ($src_ip,$src_port,$dest_ip,$dst_port,"Serv-U < v5.0.0.4 MDTM command long timezone string overflow attack!");
}
}
}
}
}
sub LogAlert {
my ($src_ip,$src_port,$dest_ip,$dst_port,$message) = @_;
printf ATTACKLOG ("%s\t%s:%s -> %s:%s\t%s\n",$nowtime,$src_ip,$src_port,$dest_ip,$dst_port,$message);
printf ("%s\t%s:%s -> %s:%s\t%s\n",$nowtime,$src_ip,$src_port,$dest_ip,$dst_port,$message);
}
sub LogMonitor {
my ($src_ip,$src_port,$dest_ip,$dst_port,$message) = @_;
printf MONITORLOG ("%s\t%s:%s -> %s:%s\t%s\n",$nowtime,$src_ip,$src_port,$dest_ip,$dst_port,$message);
printf ("%s\t%s:%s -> %s:%s\t%s\n",$nowtime,$src_ip,$src_port,$dest_ip,$dst_port,$message);
}
sub HandleINT {
exit (0);
}
sub HandleTERM {
exit (0);
}
sub CleanUp {
close (ATTACKLOG); close (MONITORLOG);
}
-------- 8< --------------