예제 #1
0
    def _portsVary(self, sPortVarying):
        """If key is not in sortingDict put key-value pairs in sortingDict and
           tablesDict,
           else merge value to existing value.
           sIPs/dIPs exist in key and value, because they could be the same ("any")
           as the one already in the hashmap and still contain different elements. 
           To provide a correct elements list they needs to be extended.
        """
        self.sortingDict.clear()
        self.tablesDict.clear()
        newR = RuleSet()
        for r in self.ruleSet:
            if sPortVarying:
                keys = (r.direction, r.sIPs, r.dIPs, r.dPorts, r.interface, r.action)
                value = (r.sPorts, r.timeStamp, r.flag, r.sIPs, r.dIPs)
            else:
               keys = (r.direction, r.sIPs, r.sPorts, r.dIPs, r.interface, r.action)
               value = (r.dPorts, r.timeStamp, r.flag, r.sIPs, r.dIPs)
            self._sortIntoDicts(keys, value)

        for key, value in self.tablesDict.iteritems():
            if sPortVarying:
                r = Rule(key[0], value[3], value[0], value[4], key[3], self.proto, key[4], key[5], self.style, value[1], value[2])
            else:
                r = Rule(key[0], value[3], key[2], value[4], value[0], self.proto, key[4], key[5], self.style,  value[1], value[2])
            newR.insert(r)

        self.ruleSet = newR
        del newR    
예제 #2
0
 def _filterRules(self, rules, checkList, proto, direction):        
     filteredRules = RuleSet()
     for s in checkList:
         if s[2] == proto or s[2] == "any":
             for r in rules.values():
                 for d in direction:
                     if r.direction == d \
                        and (s[0] in r.dIPs or s[0] == "any") \
                        and (s[1] in r.dPorts or s[1] == "any"):
                         rules.remove(r)
                         filteredRules.insert(r)
     return filteredRules 
예제 #3
0
def testRules(connections, rules, verbose=False):
    filtertConns = RuleSet()
    for c in connections:
        ruled = False
        for r in rules:
            if c.interface == r.interface and c.proto == r.proto:
                if _testPorts(c, r):
                    if _testIPs(c, r):
                        ruled = True
                        break
        if not ruled:
            if verbose:
                print "Was not matched"
                print c
            filtertConns.insert(c)   
    return filtertConns
예제 #4
0
    def _checkTcpForConns(self):
        """Checks tcp-set for connections.""" 
        print "Checking for Connections"
        tcpRuleSetConnsOnly = RuleSet()
        if self.p.linktype == self.PFLOG_DUMP:
            tcpRuleSetConnsOnly = self.tcpRuleSet
        else:
            for r in self.tcpRuleSet:
                connection = False
                for r2 in self.tcpRuleSet:
                    if (r == r2 and (r.flag[0]=="SYN") and (r2.flag[0]=="FIN")):
                        connection = True
                        break
                if connection:
                    tcpRuleSetConnsOnly.insert(r)

        self.tcpRuleSet = tcpRuleSetConnsOnly 
예제 #5
0
class PcapParser():
    """
    PcapParser parses a pcap-file with dpkt.
    Every ip-paket is put into either the tcp or udp or icmp ruleset.
    Rulesets are sets, they contain every item only once.
    Concerning tcp: only full connections are kept (there must be a syn 
    and a fin paket).
    Non-ip-pakets are not concerned. 
    """
    def __init__(self, pcapFile, action, style, direction, maxNumPortsAny, \
                 connectionChecking, portscanChecking, printElements, \
                 innerNetworks=None, ddosDetection=True): 
        self.p = pcapFile
        self.direction = direction 
        self.action = action
        self.style = style
        self.interface = "None"
        self.tcpRuleSet = RuleSet()
        self.udpRuleSet = RuleSet()
        self.icmpRuleSet = RuleSet()
        self.tcpRuleList = []
        self.udpRuleList = []
        self.icmpRuleList = []
        self.MAX_NUM_PORTS_ANY = maxNumPortsAny
        self.connectionChecking = connectionChecking
        self.ddosDetection = ddosDetection
        self.saveElements = portscanChecking or printElements
        self.PFLOG_DUMP = 117
        self.innerNetworks = innerNetworks
    
    def parsePcapFile(self):
        """Parse a pcap file"""
        for ts, buf in self.p:
            self._packetHandler(buf, ts)
        if self.connectionChecking:
            self._checkTcpForConns()
        return self.tcpRuleSet, self.udpRuleSet, self.icmpRuleSet, \
               self.tcpRuleList, self.udpRuleList, self.icmpRuleList
        
    def _packetHandler(self, buf, ts):
        """Parse a pcap buffer"""
        SINGLE_IP_SLASHSIZE = 32
        try:
            if (self.p.datalink() == self.PFLOG_DUMP):
                #pkt = dpkt.pflog.Pflog(buf)
                pkt = Pflog(buf)
                self.interface = pkt.interfaceName
                self.direction = "in" if pkt.direction == 1 else "out"
                subpkt = pkt.data
                try:
                    subpkt = dpkt.ip.IP(subpkt)
                except:
                    #skip non IP packets
                    return
            else:
                pkt = dpkt.ethernet.Ethernet(buf)
                subpkt = pkt.data
                if not isinstance(subpkt, dpkt.ip.IP):
                    #skip non IP packets
                    return

            proto = subpkt.p
            shost = socket.inet_ntoa(subpkt.src)
            dhost = socket.inet_ntoa(subpkt.dst)
            shostInner = False
            dhostInner = False
            if self.innerNetworks != None:
                for n in self.innerNetworks:
                    slashSize = str(n).split("/")[1]
                    if IPv4Network(str(shost)+"/"+str(slashSize)) == n:
                       shostInner = True 
                    if IPv4Network(dhost+"/"+slashSize) == n:
                       dhostInner = True 
                if shostInner and dhostInner:
                    self.direction = "none-inner"
                elif shostInner and not dhostInner:
                    self.direction = "out"
                elif not shostInner and dhostInner:
                    self.direction = "in"
                else:
                    self.direction = "none-outer"

        except dpkt.Error:
            #skip non-ethernet packages
            return
        try:
            if proto == socket.IPPROTO_TCP:
                try:
                    tcp = subpkt.data
                    flag = tcp.flags
                    if self.connectionChecking:
                        rightFlag = ((flag == dpkt.tcp.TH_SYN) \
                                    or (flag & dpkt.tcp.TH_FIN != 0))
                    else:
                        rightFlag = (flag == dpkt.tcp.TH_SYN)
                                    
                    dport = tcp.dport
                    sport = tcp.sport
                    sIP = IPsMap(self.saveElements)
                    sIP.insert(IPv4Address(shost))
                    sPort = PortsMap(self.MAX_NUM_PORTS_ANY, self.saveElements)
                    sPort.insert(Port(sport, True))
                    dIP = IPsMap(self.saveElements)
                    dIP.insert(IPv4Address(dhost))
                    dPort = PortsMap(self.MAX_NUM_PORTS_ANY, self.saveElements)
                    dPort.insert(Port(dport, False))
                    if flag == dpkt.tcp.TH_SYN:
                        flag = "SYN"
                    else:
                        flag = "FIN"
                    r = Rule(self.direction, sIP, sPort, dIP, dPort, "tcp", \
                             self.interface, self.action, self.style, [ts, ], [flag, ])
                    if self.p.datalink() == self.PFLOG_DUMP or rightFlag:
                        self.tcpRuleSet.insert(r)
                    if self.ddosDetection:
                        self.tcpRuleList.append((IPv4Address(shost), ts))
                except AttributeError:
                    #skip broken packages
                    return
            elif proto == socket.IPPROTO_UDP:
                udp = subpkt.data
                dport = udp.dport
                sport = udp.sport
                sIP = IPsMap(self.saveElements)
                sIP.insert(IPv4Address(shost))
                sPort = PortsMap(self.MAX_NUM_PORTS_ANY, self.saveElements)
                sPort.insert(Port(sport, True))
                dIP = IPsMap(self.saveElements)
                dIP.insert(IPv4Address(dhost))
                dPort = PortsMap(self.MAX_NUM_PORTS_ANY, self.saveElements)
                dPort.insert(Port(dport, False))
                r = Rule(self.direction, sIP, sPort, dIP, dPort, "udp", \
                         self.interface, self.action, self.style, [ts, ])
                self.udpRuleSet.insert(r)
                if self.ddosDetection:
                   self.udpRuleList.append((IPv4Address(shost), ts))
            elif proto == socket.IPPROTO_ICMP:
                sIP = IPsMap(self.saveElements)
                sIP.insert(IPv4Address(shost))
                sPort = PortsMap(self.MAX_NUM_PORTS_ANY)
                sPort.insert(Port(-1, True))
                dIP = IPsMap(self.saveElements)
                dIP.insert(IPv4Address(dhost))
                dPort = PortsMap(self.MAX_NUM_PORTS_ANY)
                dPort.insert(Port(-1, False))
                r = Rule(self.direction, sIP, sPort, dIP, dPort, "icmp", \
                         self.interface, self.action, self.style, [ts, ])
                self.icmpRuleSet.insert(r)
                if self.ddosDetection:
                   self.icmpRuleList.append((IPv4Address(shost), ts))
        except dpkt.Error:
            return

    def _checkTcpForConns(self):
        """Checks tcp-set for connections.""" 
        print "Checking for Connections"
        tcpRuleSetConnsOnly = RuleSet()
        if self.p.linktype == self.PFLOG_DUMP:
            tcpRuleSetConnsOnly = self.tcpRuleSet
        else:
            for r in self.tcpRuleSet:
                connection = False
                for r2 in self.tcpRuleSet:
                    if (r == r2 and (r.flag[0]=="SYN") and (r2.flag[0]=="FIN")):
                        connection = True
                        break
                if connection:
                    tcpRuleSetConnsOnly.insert(r)

        self.tcpRuleSet = tcpRuleSetConnsOnly 
예제 #6
0
class InfectedHostsDetector:
    """
    InfectedHostsDetector takes found portscans and policy violations 
    and tries to find indected hosts.
    """

    def __init__(self, tcpPortscans, udpPortscans, policyViolations, suspPolVio):

        self.tcpPortscans = tcpPortscans
        self.udpPortscans = udpPortscans
        self.policyViolations = policyViolations
        self.portscans = RuleSet()
        self.doubleIPs = IPsMap()
        self.portscanIPs = IPsMap()
        self.violationIPs = IPsMap()
        self.clearedPolicyViolations = RuleSet()
        self.suspPolVio = suspPolVio.split(":")

    def detectInfectedHosts(self):
        for ps in self.tcpPortscans.portscanSet:
            if ps.direction == "out" or ps.direction == "none-inner":
                self.portscans.insert(ps)
        for ps in self.udpPortscans.portscanSet:
            if ps.direction == "out" or ps.direction == "none-inner":
                self.portscans.insert(ps)
        for pv in self.policyViolations:
            if pv.direction == "out" or pv.direction == "none-inner":
                if str(pv.dPorts.values()[0].portNumber) in self.suspPolVio:
                    self.clearedPolicyViolations.insert(pv)

        for portscan in self.portscans:
            for violation in self.clearedPolicyViolations:
                if portscan.sIPs == violation.sIPs:
                    self.doubleIPs.insert(portscan.sIPs)

        for doubleIP in self.doubleIPs:
            for policyVio in self.clearedPolicyViolations.values():
                if policyVio.sIPs == doubleIP:
                    try:
                        self.clearedPolicyViolations.remove(policyVio)
                    except:
                        # already removed
                        pass

        for doubleIP in self.doubleIPs:
            for portscan in self.portscans.values():
                if portscan.sIPs == doubleIP:
                    try:
                        self.portscans.remove(portscan)
                    except:
                        # already removed
                        pass

        for violation in self.clearedPolicyViolations:
            self.violationIPs.insert(violation.sIPs)
        for portscan in self.portscans:
            self.portscanIPs.insert(portscan.sIPs)

    def printInfectedHosts(self):
        for host in self.doubleIPs:
            print "%s might be infected! Warning signals include: portscans and policy violations" % str(host)
        for host in self.portscanIPs:
            print "%s might be infected! Warning signals include: portscans" % str(host)
        for host in self.violationIPs:
            print "%s might be infected! Warning signals include: policy violations" % str(host)
예제 #7
0
class PortscanDetector(RuleGenerator):
    """
    PortscanDetector takes a ruleSet and tries to find portscans.
    """
    
    def __init__(self, ruleSet, proto, style, numChecksP, numChecksIP, \
                 numAnyP, numAnyIP, distanceRange, slashSize, ipsPerSlash, \
                 numPortsPortscan, numIPsPortscan):

        RuleGenerator.__init__(self, ruleSet, proto, style, numChecksP, numChecksIP, \
                               numAnyP, numAnyIP, distanceRange, \
                               slashSize, ipsPerSlash)

        self.MAX_NUM_PORTS_PORTSCAN = numPortsPortscan
        self.MAX_NUM_IPS_PORTSCAN = numIPsPortscan
        self.MAX_DIST_RANGE_SCAN = 65535
        self.portscanSet = RuleSet()

    def detectPortscans(self):
        self.generateRules()
        self._checkForPortscans()
        self.portscanSet.checkTables(self.NUM_CHECKS_P, self.MAX_DIST_RANGE_SCAN,\
                                     self.NUM_ANY_P, self.NUM_CHECKS_IP, \
                                     self.NUM_EXP, self.NUM_ANY_IP, \
                                     self.SLASH_SIZE, self.MIN_IPS_PER_SLASH)

    def _checkForPortscans(self):
        ruleList = self.ruleSet.values()
        for r in ruleList:
            if (len(r.dPorts.elements) > self.MAX_NUM_PORTS_PORTSCAN) and \
               (len(r.sIPs) == 1) or \
               (len(r.dIPs.elements) > self.MAX_NUM_IPS_PORTSCAN and \
               len(r.sIPs) == 1) and (len(r.dPorts.elements) == 1)\
               and not r.direction == "out":
                psr = PortscanRule(r.direction, r.sIPs, r.sPorts, r.dIPs, \
                                   r.dPorts, r.proto, r.interface, "block", \
                                   self.style, r.timeStamp, r.flag)
                self.portscanSet.insert(psr)
    
    def removeRulesContainingPortscanners(self, ruleSet):
        for r in ruleSet.values():
            for pr in self.portscanSet.values():
                for e in pr.sIPs.elements.values():   
                    if r.sIPs.values()[0] == e \
                       or r.dIPs.values()[0] == e:
                       try:
                           ruleSet.remove(r)
                       except KeyError:
                           #Is already removed
                           pass
                       break

    def generateRules(self):
        self.generateTables()
        del self.sortingDict
        del self.tablesDict

    def printRules(self):
        l = len(self.portscanSet)
        if l > 0:
            if l == 1:
                print "%d rule which results from traffic which looks like a portscan\n" % l
            else:
                print "%d rules which result from traffic which looks like portscans\n" % l
            print self.portscanSet 

    def generateTables(self):
        slashSizeBackup = self.SLASH_SIZE
        self.SLASH_SIZE = 32
        if not self.proto == "icmp":
            # 2. sport is the varying part
            sPort = True
            self._portsVary(sPort)

            # 3. dport is the varying part
            sPort = False
            self._portsVary(sPort)

        # 4. dIP is the varying part
        sIP = False
        self._ipsVary(sIP)
        self.SLASH_SIZE = slashSizeBackup
예제 #8
0
    def _ipsVaryIteration(self, ruleSet, sIPvarying):
        """If sIP=True, the checks are made assuming sIP ist the varying part
           else, the check are made assuming dIP is the varying part.
           The checks work like this:
           1. The key for a rule are the ports.
           2. If the key (ports) is not in sortingDict, the rule is added to
              sortingDict and to tablesDict.
           3. If the key (ports) is already added, it is checked if the new rule
              is belonging to the rule already added.
              Belonging to is defined as that:
              3.1 If, by putting the rule together, they would have the same IP
                  on both sides (source/destination) they don't belong together.
              3.2 If the IPs don't belong into the same size slashSize networks,
                  the rules don't belong together.
            4. If the rule can be put together by making the existing IPs into
               size slashsize networks, the IPs are made into networks.
            5. If a rule has its key already in the dict, but can not be matched
               to the existing rule, it is put into the restSet.
            sPorts/dPorts exist in key and value, because they could be the same ("any")
            as the one already in the hashmap and still contain different elements. 
            To provide a correct elements list they needs to be extended.
            """
        self.sortingDict.clear()
        self.tablesDict.clear()
        newR = RuleSet()
        restSet = RuleSet()
        for r in ruleSet:
            if sIPvarying:
                value = [r.sIPs, r.dIPs, r.sPorts, r.dPorts, r.timeStamp, r.flag]
            else:
                value = [r.dIPs, r.sIPs, r.sPorts, r.dPorts, r.timeStamp, r.flag]

            key1 = copy.deepcopy(r.dPorts)
            key2 = copy.deepcopy(r.sPorts)
            keys = (r.direction, key1, r.interface, r.action, key2)
                 
            if keys not in self.sortingDict:
                self.sortingDict[keys] = value
                self.tablesDict[keys] = value
            else:
                tmpIPs1 = IPsMap()
                tmpIPs1.extend(value[0])
                tmpIPs1.extend(self.tablesDict[keys][0])
                tmpIPs2 = IPsMap()
                tmpIPs2.extend(value[1])
                tmpIPs2.extend(self.tablesDict[keys][1])

                sPortsRandom = value[2].isRandomized and\
                               self.tablesDict[keys][2].isRandomized \
                               or not value[2].isRandomized and not \
                               self.tablesDict[keys][2].isRandomized
        
                if not tmpIPs1.ipInBoth(tmpIPs2) and sPortsRandom \
                   and self.tablesDict[keys][1].checkForJoinedNetwork(value[1], self.SLASH_SIZE):
                        self.tablesDict[keys][0].extend(value[0])
                        self.tablesDict[keys][2].extend(value[2])
                        self.tablesDict[keys][3].extend(value[3])
                        if self.proto == "tcp":
                            self.tablesDict[keys][5].extend(value[5])
                else:
                    if sIPvarying:
                        restSet.insert(Rule(keys[0], value[0], value[2], \
                                            value[1], value[3], self.proto, keys[2], keys[3], self.style,  value[4], value[5]))
                    else:
                        restSet.insert(Rule(keys[0], value[1], value[2], \
                                            value[0], value[3], self.proto, keys[2], keys[3], self.style, value[4], value[5]))
        
        for key, value in self.tablesDict.iteritems():
            if sIPvarying:
                newR.insert(Rule(key[0], value[0], value[2], value[1], \
                                 value[3], self.proto, key[2], key[3], self.style, value[4], value[5]))
            else:
                newR.insert(Rule(key[0], value[1], value[2], value[0], \
                                 value[3], self.proto, key[2], key[3], self.style, value[4], value[5]))

        return newR, restSet