- small fix for p0f_base

- lazy loading for p0f, queso and nmap knowledge databases
This commit is contained in:
pbi 2003-10-02 13:16:26 +00:00
parent a24bd1d885
commit 6012d0901a
1 changed files with 146 additions and 116 deletions

262
scapy.py
View File

@ -22,6 +22,10 @@
# #
# $Log: scapy.py,v $ # $Log: scapy.py,v $
# Revision 0.9.14.8 2003/10/02 15:16:26 pbi
# - small fix for p0f_base
# - lazy loading for p0f, queso and nmap knowledge databases
#
# Revision 0.9.14.7 2003/10/02 14:14:17 pbi # Revision 0.9.14.7 2003/10/02 14:14:17 pbi
# - added a LongField # - added a LongField
# - added classes and bonds for 802.11 # - added classes and bonds for 802.11
@ -281,7 +285,7 @@
from __future__ import generators from __future__ import generators
RCSID="$Id: scapy.py,v 0.9.14.7 2003/10/02 14:14:17 pbi Exp $" RCSID="$Id: scapy.py,v 0.9.14.8 2003/10/02 15:16:26 pbi Exp $"
VERSION = RCSID.split()[2]+"beta" VERSION = RCSID.split()[2]+"beta"
@ -3320,6 +3324,33 @@ def attach_filter(s, filter):
s.setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, bpfh) s.setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, bpfh)
#####################
## knowledge bases ##
#####################
class KnowledgeBase:
def __init__(self, filename):
self.filename = filename
self.base = None
def lazy_init(self):
self.base = ""
def reload(self, filename = None):
if filename is not None:
self.filename = filename
oldbase = self.base
self.base = None
self.lazy_init()
if self.base is None:
self.base = oldbase
def get_base(self):
if self.base is None:
self.lazy_init()
return self.base
############### ###############
## p0f stuff ## ## p0f stuff ##
@ -3340,44 +3371,44 @@ def attach_filter(s, filter):
p0f_base = [] class p0fKnowledgeBase(KnowledgeBase):
p0f_ttl_range=[255] def __init__(self, filename):
KnowledgeBase.__init__(self, filename)
def init_p0f(base=None,reset=1): self.ttl_range=[255]
global p0f_base def lazy_init(self):
global p0f_ttl_range try:
if reset: f=open(self.filename)
p0f_base=[] except IOError:
p0f_ttl_range=[255] warning("Can't open base %s" % self.filename)
if base is None: return
base = conf.p0f_base try:
try: self.base = []
f=open(base) for l in f:
except IOError: if l[0] in ["#","\n"]:
return continue
for l in f: l = tuple(l.split(":"))
if l[0] in ["#","\n"]: if len(l) < 9:
continue continue
l = tuple(l.split(":")) li = map(int,l[:8])
if len(l) < 9: if li[1] not in self.ttl_range:
continue self.ttl_range.append(li[1])
li = map(int,l[:8]) self.ttl_range.sort()
if li[1] not in p0f_ttl_range: self.base.append((li,":".join(l[8:])[:-1]))
p0f_ttl_range.append(li[1]) except:
p0f_ttl_range.sort() warning("Can't parse p0f database (new p0f version ?)")
p0f_base.append((li,":".join(l[8:])[:-1])) self.base = None
f.close() f.close()
def packet2p0f(pkt): def packet2p0f(pkt):
if not isinstance(pkt, Packet): while pkt.haslayer(IP) and pkt.haslayer(TCP):
pkt = pkt.getlayer(IP)
if isinstance(pkt.payload, TCP):
break
pkt = pkt.payload
if not isinstance(pkt, IP) or not isinstance(pkt.payload, TCP):
raise TypeError("Not a TCP/IP packet") raise TypeError("Not a TCP/IP packet")
if not isinstance(pkt, IP):
return packet2p0f(pkt.payload)
if not isinstance(pkt.payload, TCP):
raise TypeError("Not a TCP packet")
if pkt.payload.flags & 0x13 != 0x02: #S,!A,!F if pkt.payload.flags & 0x13 != 0x02: #S,!A,!F
raise TypeError("Not a syn packet") raise TypeError("Not a syn packet")
@ -3389,7 +3420,7 @@ def packet2p0f(pkt):
wscale = pkt.payload.options["WScale"] wscale = pkt.payload.options["WScale"]
else: else:
wscale = -1 wscale = -1
t = p0f_ttl_range[:] t = p0f_kdb.ttl_range[:]
t += [pkt.ttl] t += [pkt.ttl]
t.sort() t.sort()
ttl=t[t.index(pkt.ttl)+1] ttl=t[t.index(pkt.ttl)+1]
@ -3417,14 +3448,15 @@ def p0f(pkt):
"""Passive OS fingerprinting: which OS emitted this TCP SYN ? """Passive OS fingerprinting: which OS emitted this TCP SYN ?
p0f(packet) -> accuracy, [list of guesses] p0f(packet) -> accuracy, [list of guesses]
""" """
if len(p0f_base) == 0: pb = p0f_kdb.get_base()
if not pb:
warning("p0f base empty.") warning("p0f base empty.")
return [] return []
s = len(p0f_base[0][0]) s = len(pb[0][0])
r = [] r = []
min = s+1 min = s+1
sig = packet2p0f(pkt) sig = packet2p0f(pkt)
for b,name in p0f_base: for b,name in pb:
d = p0f_dist(sig,b) d = p0f_dist(sig,b)
if d < min: if d < min:
r = [] r = []
@ -3442,7 +3474,6 @@ def prnp0f(pkt):
pass pass
def pkt2uptime(pkt, HZ=100): def pkt2uptime(pkt, HZ=100):
"""Calculate the date the machine which emitted the packet booted using TCP timestamp """Calculate the date the machine which emitted the packet booted using TCP timestamp
pkt2uptime(pkt, [HZ=100])""" pkt2uptime(pkt, [HZ=100])"""
@ -3464,7 +3495,6 @@ pkt2uptime(pkt, [HZ=100])"""
## Queso stuff ## ## Queso stuff ##
################# #################
queso_base={}
def quesoTCPflags(flags): def quesoTCPflags(flags):
if flags == "-": if flags == "-":
@ -3475,45 +3505,45 @@ def quesoTCPflags(flags):
v |= 2**flv.index(i) v |= 2**flv.index(i)
return "%x" % v return "%x" % v
def init_queso(base=None, reset=1): class QuesoKnowledgeBase(KnowledgeBase):
global queso_base def lazy_init(self):
if reset: try:
queso_base = {} f = open(self.filename)
if base is None: except IOError:
base = conf.queso_base return
try: self.base = {}
f = open(base) p = None
except IOError: try:
return for l in f:
p = None l = l.strip()
for l in f: if not l or l[0] == ';':
l = l.strip() continue
if not l or l[0] == ';': if l[0] == '*':
continue if p is not None:
if l[0] == '*': p[""] = name
name = l[1:].strip()
p = self.base
continue
if l[0] not in list("0123456"):
continue
res = l[2:].split()
res[-1] = quesoTCPflags(res[-1])
res = " ".join(res)
if not p.has_key(res):
p[res] = {}
p = p[res]
if p is not None: if p is not None:
p[""] = name p[""] = name
name = l[1:].strip() except:
p = queso_base self.base = None
continue warning("Can't load queso base [%s]", self.filename)
if l[0] not in list("0123456"): f.close()
continue
res = l[2:].split()
res[-1] = quesoTCPflags(res[-1])
res = " ".join(res)
if not p.has_key(res):
p[res] = {}
p = p[res]
if p is not None:
p[""] = name
f.close()
def queso_sig(target, dport=80, timeout=3): def queso_sig(target, dport=80, timeout=3):
global queso_base p = queso_kdb.get_base()
p = queso_base
ret = [] ret = []
for flags in ["S", "SA", "F", "FA", "SF", "P", "SEC"]: for flags in ["S", "SA", "F", "FA", "SF", "P", "SEC"]:
ans, unans = sr(IP(dst=target)/TCP(dport=dport,flags=flags,seq=RandInt()), ans, unans = sr(IP(dst=target)/TCP(dport=dport,flags=flags,seq=RandInt()),
@ -3535,7 +3565,7 @@ def queso_sig(target, dport=80, timeout=3):
return ret return ret
def queso_search(sig): def queso_search(sig):
p = queso_base p = queso_kdb.get_base()
sig.reverse() sig.reverse()
ret = [] ret = []
try: try:
@ -3560,46 +3590,46 @@ queso(target, dport=80, timeout=3)"""
## nmap OS fp stuff ## ## nmap OS fp stuff ##
###################### ######################
nmap_base = []
def init_nmap(base=None, reset=1): class NmapKnowledgeBase(KnowledgeBase):
global nmap_base def lazy_init(self):
if reset: try:
nmap_base=[] f=open(self.filename)
if base is None: except IOError:
base = conf.nmap_base return
try:
f=open(base)
except IOError:
return
name = None self.base = []
for l in f: name = None
l = l.strip() try:
if not l or l[0] == "#": for l in f:
continue l = l.strip()
if l[:12] == "Fingerprint ": if not l or l[0] == "#":
continue
if l[:12] == "Fingerprint ":
if name is not None:
self.base.append((name,sig))
name = l[12:].strip()
sig={}
p = self.base
continue
op = l.find("(")
cl = l.find(")")
if op < 0 or cl < 0:
warning("error reading nmap os fp base file")
continue
test = l[:op]
s = map(lambda x: x.split("="), l[op+1:cl].split("%"))
si = {}
for n,v in s:
si[n] = v
sig[test]=si
if name is not None: if name is not None:
nmap_base.append((name,sig)) self.base.append((name,sig))
name = l[12:].strip() except:
sig={} self.base = None
p = nmap_base warning("Can't read nmap database [%s](new nmap version ?)" % base.filename)
continue f.close()
op = l.find("(")
cl = l.find(")")
if op < 0 or cl < 0:
warning("error reading nmap os fp base file")
continue
test = l[:op]
s = map(lambda x: x.split("="), l[op+1:cl].split("%"))
si = {}
for n,v in s:
si[n] = v
sig[test]=si
if name is not None:
nmap_base.append((name,sig))
f.close()
def TCPflags2str(f): def TCPflags2str(f):
fl="FSRPAUEC" fl="FSRPAUEC"
s="" s=""
@ -3698,7 +3728,7 @@ def nmap_probes2sig(tests):
def nmap_search(sigs): def nmap_search(sigs):
guess = 0,[] guess = 0,[]
for os,fp in nmap_base: for os,fp in nmap_kdb.get_base():
c = 0.0 c = 0.0
for t in sigs.keys(): for t in sigs.keys():
if t in fp: if t in fp:
@ -4065,6 +4095,6 @@ except_filter : BPF filter for packets to ignore
conf=Conf() conf=Conf()
init_p0f() p0f_kdb = p0fKnowledgeBase(conf.p0f_base)
init_queso() queso_kdb = QuesoKnowledgeBase(conf.queso_base)
init_nmap() nmap_kdb = NmapKnowledgeBase(conf.nmap_base)