PortDog端口扫描异常检测工具源码简析

总览

首先获取要捕获的网卡的流量(其实这个不太好,因为我们要检测的网卡不一定排在第一啊,这个可以根据自己的实际情况修改)

1
LANip = commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]

作者捕获用的是socket,因为是AF_PACKET在windows用不了,所以这种方式就只能在linux用了

1
2
3
s = socket.socket( socket.AF_PACKET , socket.SOCK_RAW , socket.ntohs(0x0003))
packet = s.recvfrom(65565)
packet = packet[0]

捕获数据后接下来就是去解析ip,tcp协议的一些字段

下一步就是检测是不是三次握手的包,是3次握手才会将信息插入到threewayhandshake数组

1
2
3
testdata = s_addr+":"+str(source_port)+"->"+d_addr+":"+str(dest_port)
if(testdata not in threewayhandshake):
threewaycheck(s_addr,d_addr,source_port,dest_port,seq_numb,dest_numb,tcp_flags)

接下来核心的就是scancheck函数

1
scancheck(s_addr,d_addr,source_port,dest_port,seq_numb,dest_numb,tcp_flags)

具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def scancheck(sip,dip,sport,dport,seqnum,acknum,flags):
global data,dataforthreewaycheck,dbdata,reverse
data = sip+":"+str(sport)+"->"+dip+":"+str(dport)+"_"+str(seqnum)+"_"+str(acknum)+"_"+"/".join(flags)
dataforthreewaycheck = sip+":"+str(sport)+"->"+dip+":"+str(dport)
revthreeway = dip+":"+str(dport)+"->"+sip+":"+str(sport)
dbdata = sip+"->"+dip
reverse = dip+"->"+sip
if(halfconnectscan(sip,dip,sport,dport,seqnum,acknum,flags)):
returned = halfconnectscan(sip,dip,sport,dport,seqnum,acknum,flags)
if(isinstance(returned,(str))):
print returned
else:
print bgcolors.BOLD+bgcolors.OKBLUE+revthreeway+bgcolors.ENDC+bgcolors.WARNING+bgcolors.BOLD+" Port Scanning Detected: [Style not Defined]:Attempt to connect closed port!"+bgcolors.ENDC
elif(fullconnectscan(sip,dip,sport,dport,seqnum,acknum,flags)):
returned = fullconnectscan(sip,dip,sport,dport,seqnum,acknum,flags)
if(isinstance(returned,(str))):
print returned
else:
print bgcolors.BOLD+bgcolors.OKBLUE+revthreeway+bgcolors.ENDC+bgcolors.WARNING+bgcolors.BOLD+" Port Scanning Detected: [Style not Defined]:Attempt to connect closed port!"+bgcolors.ENDC
elif(xmasscan(sip,dip,sport,dport,seqnum,acknum,flags)):
print bgcolors.BOLD+bgcolors.OKBLUE+dataforthreewaycheck+bgcolors.ENDC +bgcolors.BOLD+bgcolors.FAIL+ " => [Runtime Detection:] XMAS scan detected!"+bgcolors.ENDC
elif(finscan(sip,dip,sport,dport,seqnum,acknum,flags)):
print bgcolors.BOLD+bgcolors.OKBLUE+ dataforthreewaycheck+bgcolors.ENDC+ bgcolors.BOLD+bgcolors.FAIL+" => [Runtime Detection:] FIN scan detected!"+bgcolors.ENDC
elif(nullscan(sip,dip,sport,dport,seqnum,acknum,flags)):
print bgcolors.BOLD+bgcolors.OKBLUE+dataforthreewaycheck +bgcolors.ENDC+bgcolors.BOLD+bgcolors.FAIL+ " => [Runtime Detection:] NULL scan detected!"+bgcolors.ENDC

那么其实就是依次判断每种端口扫描技术

对于每种扫描,通用的就是将扫描的目标端口记录下来

1
2
3
4
5
if(scannedports.has_key(dip)):
scannedports[dip].append(str(sport))
else:
scannedports[dip] = []
scannedports[dip].append(str(sport))

下面依次看每种扫描技术判断,只要发现了,就加到黑名单

halfconnectscan(半连接扫描)

就是发SYN包,之后发了个含RST,ACK的包,那就是半连接扫描了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if("SYN" in flags and seqnum>0 and acknum==0 and len(flags)==1):
halfscandb[dbdata+"_"+str(seqnum)] = dbdata+"_SYN_ACK_"+str(seqnum)+"_"+str(acknum)
elif("RST" in flags and "ACK" in flags and len(flags)==2):
if(halfscandb.has_key(reverse+"_"+str(acknum-1))):
del halfscandb[reverse+"_"+str(acknum-1)]
if(str(dip) not in blacklist):
blacklist.append(str(dip))

return True
elif("SYN" in flags and "ACK" in flags and len(flags)==2):
if(halfscandb.has_key(reverse+"_"+str(acknum-1))):
del halfscandb[reverse+"_"+str(acknum-1)]
halfscandb[reverse+"_"+str(acknum)] = dbdata+"_RST_"+str(seqnum)+"_"+str(acknum)
elif("RST" in flags and len(flags)==1):
if(halfscandb.has_key(dbdata+"_"+str(seqnum))):
if(str(dip) not in blacklist):
blacklist.append(str(dip))

return bgcolors.BOLD+bgcolors.OKBLUE+sip+":"+str(sport)+"->"+dip+":"+str(dport) +bgcolors.ENDC+ bgcolors.BOLD+bgcolors.FAIL+" => [Runtime Detection:] Half connect(SYN scan) scan detected!"+bgcolors.ENDC
return False

fullconnectscan

这个分了两种

第一种:有三次握手,但是之后就发了ACK RST

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if(dataforthreewaycheck in threewayhandshake):
if("ACK" in flags and "RST" in flags and len(flags)==2):
if(fullscandb.has_key(dbdata)):
counter = int(fullscandb[dbdata])
if(counter>=3):

if(str(dip) not in blacklist):
blacklist.append(str(dip))
return bgcolors.BOLD+bgcolors.OKBLUE+ dip+":"+str(dport)+"->"+sip+":"+str(sport)+bgcolors.ENDC+ bgcolors.BOLD+bgcolors.FAIL+" => [Runtime Detection:] Full connect scan detected!"+bgcolors.ENDC
else:
counter = counter + 1
fullscandb[dbdata] = str(counter)
else:
counter = 0
fullscandb[dbdata] = str(counter)

第二种情况

这是连续3次在SYN后发了”RST” and “ACK”,这个我感觉还是半连接的感觉啊

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
else:
if("SYN" in flags and len(flags)==1):
if(seqnum>0 and acknum==0):
fullscandb[dbdata+"_SYN"] = str(seqnum)+"_"+str(acknum)+"_"+str(sport)+"_"+str(dport)

elif("RST" in flags and "ACK" in flags and len(flags)==2):
if(fullscandb.has_key(dip+"->"+sip+"_SYN")):
manage = fullscandb[dip+"->"+sip+"_SYN"]
pieces = manage.split("_")
old_acknum = int(pieces[1])
old_seqnum = int(pieces[0])
if(seqnum==0 and acknum==old_seqnum+1):
if(fullscandb.has_key(dbdata)):
counter = int(fullscandb[dbdata])
if(counter>=3):

if(str(dip) not in blacklist):
blacklist.append(str(dip))
return True
else:
counter = counter + 1
fullscandb[dbdata] = str(counter)
else:
counter = 0
fullscandb[dbdata] = str(counter)

xmasscan

只含下面3个flag的

“FIN” ,”URG” , “PSH”

finscan

这个没三次握手的前提下就只有一个FIN

1
2
if(dataforthreewaycheck not in threewayhandshake):
if("FIN" in flags and len(flags)==1):

nullscan

没有一个flag置位

1
if(len(flags)==0):

ackscan

只有ack

1
if("ACK" in flags and len(flags)==1):

reference

https://github.com/puniaze/PortDog

自愿打赏专区