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
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
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
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
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