Example #1
0
def udp_decoder():
    manager = AuditManager()

    conf = manager.get_configuration(UDP_NAME)
    checksum_check = conf['checksum_check']

    def udp(mpkt):
        mpkt.l4_len = UDP_LENGTH
        mpkt.l4_src, \
        mpkt.l4_dst = mpkt.get_fields('udp', ('sport', 'dport'))

        load = mpkt.get_field('udp')[mpkt.l4_len:]

        if load:
            mpkt.data = load

        if checksum_check:
            udpraw = mpkt.get_field('udp')

            if udpraw:
                if mpkt.payload_len == len(udpraw):
                    psdhdr = pack("!4s4sHH",
                                  inet_aton(mpkt.l3_src),
                                  inet_aton(mpkt.l3_dst),
                                  mpkt.l4_proto,
                                  mpkt.payload_len)

                    chksum = checksum(psdhdr + udpraw[:6] + \
                                      '\x00\x00' + udpraw[8:])

                    if mpkt.get_field('udp.chksum') != chksum:
                        mpkt.set_cfield('good_checksum', hex(chksum))
                        manager.user_msg(
                            _("Invalid UDP packet from %s to %s : " \
                              "wrong checksum %s instead of %s") %  \
                            (mpkt.l3_src, mpkt.l3_dst,              \
                             hex(mpkt.get_field('udp.chksum', 0)),  \
                             hex(chksum)),                          \
                            5, UDP_NAME)

        manager.run_decoder(APP_LAYER, PL_DEFAULT, mpkt)

        if mpkt.flags & MPKT_MODIFIED and \
           mpkt.flags & MPKT_FORWARDABLE:

            mpkt.set_field('udp.chksum', None)

        return None

    return udp
Example #2
0
def udp_decoder():
    manager = AuditManager()

    conf = manager.get_configuration(UDP_NAME)
    checksum_check = conf['checksum_check']

    def udp(mpkt):
        mpkt.l4_len = UDP_LENGTH
        mpkt.l4_src, \
        mpkt.l4_dst = mpkt.get_fields('udp', ('sport', 'dport'))

        load = mpkt.get_field('udp')[mpkt.l4_len:]

        if load:
            mpkt.data = load

        if checksum_check:
            udpraw = mpkt.get_field('udp')

            if udpraw:
                if mpkt.payload_len == len(udpraw):
                    psdhdr = pack("!4s4sHH", inet_aton(mpkt.l3_src),
                                  inet_aton(mpkt.l3_dst), mpkt.l4_proto,
                                  mpkt.payload_len)

                    chksum = checksum(psdhdr + udpraw[:6] + \
                                      '\x00\x00' + udpraw[8:])

                    if mpkt.get_field('udp.chksum') != chksum:
                        mpkt.set_cfield('good_checksum', hex(chksum))
                        manager.user_msg(
                            _("Invalid UDP packet from %s to %s : " \
                              "wrong checksum %s instead of %s") %  \
                            (mpkt.l3_src, mpkt.l3_dst,              \
                             hex(mpkt.get_field('udp.chksum', 0)),  \
                             hex(chksum)),                          \
                            5, UDP_NAME)

        manager.run_decoder(APP_LAYER, PL_DEFAULT, mpkt)

        if mpkt.flags & MPKT_MODIFIED and \
           mpkt.flags & MPKT_FORWARDABLE:

            mpkt.set_field('udp.chksum', None)

        return None

    return udp
Example #3
0
def icmp_decoder():
    manager = AuditManager()

    conf = manager.get_configuration('decoder.icmp')
    checksum_check = conf['checksum_check']

    def icmp(mpkt):
        if not checksum_check:
            return None

        if mpkt.get_field('ip.flags', 0) & 1:
            # Only a fragment
            return None

        payload = mpkt.cfields.get('reassembled_payload', None)

        if not payload:
            payload = mpkt.get_field('icmp')

            if not payload:
                return None

        cur_chksum = hex(unpack("!H", payload[2:4])[0])
        icmpraw = payload[0:2] + '\x00\x00' + payload[4:]
        com_chksum = hex(checksum(icmpraw))

        if com_chksum != cur_chksum:
            mpkt.set_cfield('good_checksum', com_chksum)
            manager.user_msg(_("Invalid ICMP packet from %s to %s : " \
                               "wrong checksum %s instead of %s") %  \
                             (mpkt.get_field('ip.src'),          \
                              mpkt.get_field('ip.dst'),          \
                              cur_chksum, com_chksum),
                             5, 'decoder.icmp')

        return None

    return icmp
Example #4
0
def icmp_decoder():
    manager = AuditManager()

    conf = manager.get_configuration('decoder.icmp')
    checksum_check = conf['checksum_check']

    def icmp(mpkt):
        if not checksum_check:
            return None

        if mpkt.get_field('ip.flags', 0) & 1:
            # Only a fragment
            return None

        payload = mpkt.cfields.get('reassembled_payload', None)

        if not payload:
            payload = mpkt.get_field('icmp')

            if not payload:
                return None

        cur_chksum = hex(unpack("!H", payload[2:4])[0])
        icmpraw = payload[0:2] + '\x00\x00' + payload[4:]
        com_chksum = hex(checksum(icmpraw))

        if com_chksum != cur_chksum:
            mpkt.set_cfield('good_checksum', com_chksum)
            manager.user_msg(_("Invalid ICMP packet from %s to %s : " \
                               "wrong checksum %s instead of %s") %  \
                             (mpkt.get_field('ip.src'),          \
                              mpkt.get_field('ip.dst'),          \
                              cur_chksum, com_chksum),
                             5, 'decoder.icmp')

        return None

    return icmp
Example #5
0
def ip_decoder():
    manager = AuditManager()

    conf = manager.get_configuration('decoder.ip')
    checksum_check, reassemble, max_len, max_frags = \
        conf['checksum_check'], conf['reassemble'], \
        conf['reassemble_max_fraglist'], conf['reassemble_max_fragments']

    reas_dict = {}

    def ip_reassemble(mpkt):
        # Here we have to check for fragmentation
        # by creating a dict to holds id of ip packets
        # and set mpkt.lock() on it if mpkg is MF
        # until the resegmentation is done.
        # If it's a fragment we have to return None
        # to break the chain.

        # TODO: check ip.flags standard name in UMPA
        ts = time.time()
        mf = mpkt.get_field('ip.flags', 0) & 1
        frag_off = mpkt.get_field('ip.frag', 0) * 8

        if not mf and frag_off == 0:
            return False

        ipid = mpkt.get_field('ip.id')

        if ipid in reas_dict:
            plist = reas_dict[ipid]

            if len(plist) >= max_frags:
                del reas_dict[ipid]
                manager.user_msg(_('Dropping out the sequence with ID: '
                                   '%s due reassemble_max_fragments') %
                                 ipid, 7, 'decoder.ip')

                return False

            ret = 0
            idx = 0
            inserted = False

            while idx < len(plist):
                ts2, frag_off2, mpkt2 = plist[idx]

                if frag_off2 == frag_off:
                    plist[idx] = (ts, frag_off, mpkt.copy())
                    break
                elif frag_off2 < frag_off:
                    ret += frag_off2
                    idx += 1
                    continue

                inserted = True
                plist.insert(idx, (ts, frag_off, mpkt.copy()))
                break

            if not inserted:
                plist.append((ts, frag_off, mpkt.copy()))

            # Now let's get the last packet and see if MF = 0
            # EVASION!
            if plist[-1][-1].get_field('ip.flags') & 1 == 0:

                if idx == len(plist) -1:
                    ret = frag_off - ret
                else:
                    while idx < len(plist) - 1:
                        ts2, frag_off2, mpkt2 = plist[idx]
                        ret += frag_off2
                        idx += 1

                        ret = plist[-1][1] - ret

                if ret == 0:
                    log.debug('Reassembling sequence with ID: %s' % \
                              ipid)

                    reas_payload = ''

                    for ts2, frag_off2, mpkt2 in plist:
                        try:
                            ihl = mpkt2.l3_len
                            reas_payload += mpkt2.get_field('ip')[ihl:]
                        except:
                            pass

                    # Ok check that we have a complete payload
                    ihl = mpkt.l3_len
                    p_len = frag_off + mpkt.get_field('ip.len') - ihl

                    if len(reas_payload) != p_len:
                        mpkt.set_cfield('reassembled_payload', None)
                        manager.user_msg(_('Reassemble of IP packet ' \
                                           'from %s to %s failed') %  \
                                         (mpkt.l3_src, mpkt.l3_dst),  \
                                         4, 'decoder.ip')

                    # Nice drop out everythin!
                    del reas_dict[ipid]

                    mpkt.set_cfield('reassembled_payload', reas_payload)
                    return True
        else:
            if len(reas_dict) >= max_len:
                # Ok just drop the list with the minor ts (the oldest)
                min_k = min([(v, k) for k, v in reas_dict.items()])[1]
                del reas_dict[min_k]

                # Debug
                manager.user_msg(_('Dropping out the oldest sequence '
                                   'with ID: %s') % min_k,
                                 7, 'decoder.ip')

            log.debug('First packet of the sequence with ID: %s' % ipid)
            reas_dict[ipid] = [(ts, frag_off, mpkt)]

        return False

    def ip(mpkt):
        mpkt.l3_src, \
        mpkt.l3_dst, \
        mpkt.l4_proto = mpkt.get_fields('ip', ('src', 'dst', 'proto'))

        # TODO: handle IPv6

        ipraw = mpkt.get_field('ip')

        if not ipraw:
            return

        mpkt.l3_len = mpkt.get_field('ip.ihl') * 4
        mpkt.payload_len = mpkt.get_field('ip.len') - mpkt.l3_len

        if mpkt.context:
            mpkt.context.check_forwarded(mpkt)

            if mpkt.flags & MPKT_FORWARDED:
                return None

            mpkt.context.set_forwardable(mpkt)

        iplen = min(20, len(ipraw))

        if mpkt.get_field('ip.len') > len(ipraw):
            # Probably we are capturing with low snaplen
            # so the packets are not fully captured. Avoid
            # further calculation.
            return PROTO_LAYER, mpkt.l4_proto

        if checksum_check:
            ihl = max(20, mpkt.l3_len)
            pkt = ipraw[:10] + '\x00\x00' + ipraw[12:ihl]

            chksum = checksum(pkt)

            # Probably here it's better to set also a cfield
            # and to turn False the checksum_check default value
            if mpkt.get_field('ip.chksum') != chksum:
                mpkt.set_cfield('good_checksum', hex(chksum))
                manager.user_msg(_("Invalid IP packet from %s to %s : " \
                                   "wrong checksum %s instead of %s") %  \
                                 (mpkt.l3_src, mpkt.l3_dst,          \
                                  hex(mpkt.get_field('ip.chksum')),  \
                                  hex(chksum)),
                                 5, 'decoder.ip')

            elif reassemble:
                ip_reassemble(mpkt)

        ident = IPIdent.create(mpkt)
        sess = SessionManager().get_session(ident)

        if not sess:
            sess = Session(ident)
            sess.data = IPStatus()
            SessionManager().put_session(sess)

        sess.prev = mpkt.session
        mpkt.session = sess

        status = sess.data
        status.last_id = mpkt.get_field('ip.id', 0)

        manager.run_decoder(PROTO_LAYER, mpkt.l4_proto, mpkt)

        if mpkt.flags & MPKT_DROPPED:
            status.id_adj -= 1
        elif mpkt.flags & MPKT_MODIFIED or status.id_adj != 0:
            mpkt.set_field('ip.id', mpkt.get_field('ip.id', 0) + status.id_adj)
            mpkt.set_field('ip.len', mpkt.get_field('ip.len', 0) + mpkt.inj_delta)
            mpkt.set_field('ip.chksum', None)

    return ip
Example #6
0
class TCPDecoder(Plugin, PassiveAudit):
    def start(self, reader):
        self.checksum_check = True
        self.reassembler = None
        self.manager = None

    def stop(self):
        manager = AuditManager()
        manager.remove_decoder(PROTO_LAYER, NL_TYPE_TCP, self._process_tcp)
        manager.remove_injector(1, NL_TYPE_TCP, self._inject_tcp)

        try:
            manager.remove_decoder_hook(PROTO_LAYER, NL_TYPE_ICMP,
                                             self.reassembler.process_icmp, 1)
        except:
            pass

    def register_decoders(self):
        self.manager = AuditManager()
        conf = self.manager.get_configuration('decoder.tcp')

        self.checksum_check = conf['checksum_check']

        self.manager.add_decoder(PROTO_LAYER, NL_TYPE_TCP, self._process_tcp)
        self.manager.add_injector(1, NL_TYPE_TCP, self._inject_tcp)

        if conf['enable_reassemble']:
            self.reassembler = Reassembler(conf['reassemble_workarounds'],
                                           conf['reassemble_maxstreams'])
            self.manager.add_decoder_hook(PROTO_LAYER, NL_TYPE_ICMP,
                                          self.reassembler.process_icmp, 1)

    def _inject_tcp(self, context, mpkt, length):
        """
        Function that manages injection of fragments in active TCP connection
        """

        ident = TCPIdent.create(mpkt)
        sess = SessionManager().get_session(ident)

        if not sess:
            log.debug("No TCP session found.")
            return False, length

        if ident.l3_src == sess.ident.l3_src:
            status = sess.data[1]
            ostatus = sess.data[0]
        else:
            status = sess.data[0]
            ostatus = sess.data[1]

        mpkt.set_fields('tcp', {
            'sport' : mpkt.l4_src,
            'dport' : mpkt.l4_dst,
            'dataofs' : 5,
            'chksum' : None,
            'urgptr' : 0,
            'flags' : TH_PSH,
            'options' : {}})

        if status.injectable & INJ_FIN or \
           not status.injectable & INJ_FWD or \
           not ostatus.injectable & INJ_FWD:
            log.debug("Session is not injectable.")
            return False, length

        mpkt.set_fields('tcp', {
            'seq' : status.last_seq + status.seq_adj,
            'ack' : status.last_ack - ostatus.seq_adj})

        if status.last_ack != 0:
            mpkt.set_field('tcp.flags', mpkt.l4_flags | TH_ACK)

        mpkt.session = sess.prev
        length += 20 + mpkt.l2_len

        injector = AuditManager().get_injector(0, mpkt.session.ident.magic)
        is_ok, length = injector(context, mpkt, length)

        if not is_ok:
            return is_ok, length

        length = context.get_mtu() - length

        if length > mpkt.inject_len:
            length = mpkt.inject_len

        payload = mpkt.inject[:length]
        payload_pkt = MetaPacket.new('raw')
        payload_pkt.set_field('raw.load', payload)
        mpkt.add_to('tcp', payload_pkt)

        status.seq_adj += length
        mpkt.data_len = length

        return True, length

    def _process_tcp(self, mpkt):
        mpkt.l4_src, \
        mpkt.l4_dst, \
        mpkt.l4_ack, \
        mpkt.l4_seq, \
        mpkt.l4_flags = mpkt.get_fields('tcp', ('sport', 'dport', 'ack', \
                                                'seq', 'flags'))
        mpkt.l4_len = mpkt.get_field('tcp.dataofs', 5) * 4

        if mpkt.l4_src is None:
            return None

        tcpraw = mpkt.get_field('tcp')

        if tcpraw:
            mpkt.data_len = mpkt.payload_len - mpkt.l4_len
            mpkt.data = tcpraw[mpkt.l4_len:]

        wrong = False

        if self.checksum_check and tcpraw:
            if mpkt.payload_len == len(tcpraw):
                ip_src = mpkt.l3_src
                ip_dst = mpkt.l3_dst

                psdhdr = pack("!4s4sHH",
                              inet_aton(ip_src),
                              inet_aton(ip_dst),
                              mpkt.l4_proto,
                              mpkt.payload_len)

                chksum = checksum(psdhdr + tcpraw[:16] + \
                                  "\x00\x00" + tcpraw[18:])

                if mpkt.get_field('tcp.chksum', 0) != chksum:
                    wrong = True
                    mpkt.set_cfield('good_checksum', hex(chksum))
                    self.manager.user_msg(
                                _("Invalid TCP packet from %s to %s : " \
                                  "wrong checksum %s instead of %s") %  \
                                (ip_src, ip_dst,                        \
                                 hex(mpkt.get_field('tcp.chksum', 0)),  \
                                 hex(chksum)),
                                5, 'decoder.tcp')

        if wrong:
            self.manager.run_decoder(APP_LAYER, PL_DEFAULT, mpkt)
            return None

        if self.reassembler:
            self.reassembler.process_tcp(mpkt)

        ident = TCPIdent.create(mpkt)
        sess = SessionManager().get_session(ident)

        if not sess:
            sess = Session(ident)
            sess.data = (TCPStatus(), TCPStatus())
            SessionManager().put_session(sess)

        sess.prev = mpkt.session
        mpkt.session = sess

        if ident.l3_src == sess.ident.l3_src:
            status = sess.data[1]
            ostatus = sess.data[0]
        else:
            status = sess.data[0]
            ostatus = sess.data[1]

        status.last_seq = mpkt.l4_seq + mpkt.data_len

        if mpkt.l4_flags & TH_ACK:
            status.last_ack = mpkt.l4_ack

        if mpkt.l4_flags & TH_SYN:
            status.last_seq += 1

        if mpkt.l4_flags & TH_RST:
            status.injectable |= INJ_FIN
            ostatus.injectable |= INJ_FIN

        if mpkt.flags & MPKT_FORWARDABLE:
            status.injectable |= INJ_FWD
        elif status.injectable & INJ_FWD:
            status.injectable ^= INJ_FWD

        self.manager.run_decoder(APP_LAYER, PL_DEFAULT, mpkt)

        if mpkt.l4_flags & TH_FIN:
            status.injectable |= INJ_FIN

        if mpkt.flags & MPKT_DROPPED and mpkt.flags & MPKT_FORWARDABLE:
            status.seq_adj += mpkt.inj_delta
        elif (mpkt.flags & MPKT_MODIFIED or \
             status.seq_adj != 0 or ostatus != 0) and \
             mpkt.flags & MPKT_FORWARDABLE:

            mpkt.set_field('tcp.seq', mpkt.l4_seq + status.seq_adj)
            mpkt.set_field('tcp.ack', mpkt.l4_ack - ostatus.seq_adj)

            status.seq_adj += mpkt.inj_delta

            mpkt.set_field('tcp.chksum', None)

        return None
Example #7
0
def ip_decoder():
    manager = AuditManager()

    conf = manager.get_configuration('decoder.ip')
    checksum_check, reassemble, max_len, max_frags = \
        conf['checksum_check'], conf['reassemble'], \
        conf['reassemble_max_fraglist'], conf['reassemble_max_fragments']

    reas_dict = {}

    def ip_reassemble(mpkt):
        # Here we have to check for fragmentation
        # by creating a dict to holds id of ip packets
        # and set mpkt.lock() on it if mpkg is MF
        # until the resegmentation is done.
        # If it's a fragment we have to return None
        # to break the chain.

        # TODO: check ip.flags standard name in UMPA
        ts = time.time()
        mf = mpkt.get_field('ip.flags', 0) & 1
        frag_off = mpkt.get_field('ip.frag', 0) * 8

        if not mf and frag_off == 0:
            return False

        ipid = mpkt.get_field('ip.id')

        if ipid in reas_dict:
            plist = reas_dict[ipid]

            if len(plist) >= max_frags:
                del reas_dict[ipid]
                manager.user_msg(
                    _('Dropping out the sequence with ID: '
                      '%s due reassemble_max_fragments') % ipid, 7,
                    'decoder.ip')

                return False

            ret = 0
            idx = 0
            inserted = False

            while idx < len(plist):
                ts2, frag_off2, mpkt2 = plist[idx]

                if frag_off2 == frag_off:
                    plist[idx] = (ts, frag_off, mpkt.copy())
                    break
                elif frag_off2 < frag_off:
                    ret += frag_off2
                    idx += 1
                    continue

                inserted = True
                plist.insert(idx, (ts, frag_off, mpkt.copy()))
                break

            if not inserted:
                plist.append((ts, frag_off, mpkt.copy()))

            # Now let's get the last packet and see if MF = 0
            # EVASION!
            if plist[-1][-1].get_field('ip.flags') & 1 == 0:

                if idx == len(plist) - 1:
                    ret = frag_off - ret
                else:
                    while idx < len(plist) - 1:
                        ts2, frag_off2, mpkt2 = plist[idx]
                        ret += frag_off2
                        idx += 1

                        ret = plist[-1][1] - ret

                if ret == 0:
                    log.debug('Reassembling sequence with ID: %s' % \
                              ipid)

                    reas_payload = ''

                    for ts2, frag_off2, mpkt2 in plist:
                        try:
                            ihl = mpkt2.l3_len
                            reas_payload += mpkt2.get_field('ip')[ihl:]
                        except:
                            pass

                    # Ok check that we have a complete payload
                    ihl = mpkt.l3_len
                    p_len = frag_off + mpkt.get_field('ip.len') - ihl

                    if len(reas_payload) != p_len:
                        mpkt.set_cfield('reassembled_payload', None)
                        manager.user_msg(_('Reassemble of IP packet ' \
                                           'from %s to %s failed') %  \
                                         (mpkt.l3_src, mpkt.l3_dst),  \
                                         4, 'decoder.ip')

                    # Nice drop out everythin!
                    del reas_dict[ipid]

                    mpkt.set_cfield('reassembled_payload', reas_payload)
                    return True
        else:
            if len(reas_dict) >= max_len:
                # Ok just drop the list with the minor ts (the oldest)
                min_k = min([(v, k) for k, v in reas_dict.items()])[1]
                del reas_dict[min_k]

                # Debug
                manager.user_msg(
                    _('Dropping out the oldest sequence '
                      'with ID: %s') % min_k, 7, 'decoder.ip')

            log.debug('First packet of the sequence with ID: %s' % ipid)
            reas_dict[ipid] = [(ts, frag_off, mpkt)]

        return False

    def ip(mpkt):
        mpkt.l3_src, \
        mpkt.l3_dst, \
        mpkt.l4_proto = mpkt.get_fields('ip', ('src', 'dst', 'proto'))

        # TODO: handle IPv6

        ipraw = mpkt.get_field('ip')

        if not ipraw:
            return

        mpkt.l3_len = mpkt.get_field('ip.ihl') * 4
        mpkt.payload_len = mpkt.get_field('ip.len') - mpkt.l3_len

        if mpkt.context:
            mpkt.context.check_forwarded(mpkt)

            if mpkt.flags & MPKT_FORWARDED:
                return None

            mpkt.context.set_forwardable(mpkt)

        iplen = min(20, len(ipraw))

        if mpkt.get_field('ip.len') > len(ipraw):
            # Probably we are capturing with low snaplen
            # so the packets are not fully captured. Avoid
            # further calculation.
            return PROTO_LAYER, mpkt.l4_proto

        if checksum_check:
            ihl = max(20, mpkt.l3_len)
            pkt = ipraw[:10] + '\x00\x00' + ipraw[12:ihl]

            chksum = checksum(pkt)

            # Probably here it's better to set also a cfield
            # and to turn False the checksum_check default value
            if mpkt.get_field('ip.chksum') != chksum:
                mpkt.set_cfield('good_checksum', hex(chksum))
                manager.user_msg(_("Invalid IP packet from %s to %s : " \
                                   "wrong checksum %s instead of %s") %  \
                                 (mpkt.l3_src, mpkt.l3_dst,          \
                                  hex(mpkt.get_field('ip.chksum')),  \
                                  hex(chksum)),
                                 5, 'decoder.ip')

            elif reassemble:
                ip_reassemble(mpkt)

        ident = IPIdent.create(mpkt)
        sess = SessionManager().get_session(ident)

        if not sess:
            sess = Session(ident)
            sess.data = IPStatus()
            SessionManager().put_session(sess)

        sess.prev = mpkt.session
        mpkt.session = sess

        status = sess.data
        status.last_id = mpkt.get_field('ip.id', 0)

        manager.run_decoder(PROTO_LAYER, mpkt.l4_proto, mpkt)

        if mpkt.flags & MPKT_DROPPED:
            status.id_adj -= 1
        elif mpkt.flags & MPKT_MODIFIED or status.id_adj != 0:
            mpkt.set_field('ip.id', mpkt.get_field('ip.id', 0) + status.id_adj)
            mpkt.set_field('ip.len',
                           mpkt.get_field('ip.len', 0) + mpkt.inj_delta)
            mpkt.set_field('ip.chksum', None)

    return ip