当前位置: 首页 > 工具软件 > Packet-Agent > 使用案例 >

OSSIM-agent源代码分析(十二)

安浩瀚
2023-12-01

2021SC@SDUSC

PacketUtils.py
OSSIM-agent源代码分析(十二)

简述

OSSIM Agent的主要职责是收集网络上存在的各种设备发送的所有数据,然后按照一种标准方式(standardized way)有序的发送给OSSIM Server,Agent收集到数据后在发送给Server之前要对这些数据进行标准化处理,这样Server就可以依一种统一的方式来处理这些信息,并且也简化了Server的处理过程。

PacketUtils是包处理函数,在对大量数据收集后,处理数据和检索包能力非常重要的一项工作。

OSSIM作为检测工具,基本的处理和检索功能的完备就是非常重要的一环

相关代码

初始导报:

from binascii import hexlify
import socket, struct, sys
import time
from Logger import Logger
from Utils import dumphexdata
logger = Logger.logger

UDPPacket类

初始化方法,初始化数据,将payload和其他关键数据存入对象中

def __init__(self, data):
        self._data = data
        (self.sport, self.dport, self.length, self.checksum) = struct.unpack(">HHHH", data[0:8])
        self._payload = data[8:]

payload get函数

def getpayload(self):
        return self._payload

转存函数,打印相关信息,调用dumpexdata函数

 def dump(self):
        print "UDP Header"
        print "SPORT:%u DPORT:%u LENGTH:%04x CHECKSUM:%04x" % (self.sport, self.dport, self.length, self.checksum)
        print "Payload"
        dumphexdata(self._payload)

str函数,通过正则表达式,匹配对应的字符串

   def __str__(self):
        st = """ udp_sport="%u" udp_dport="%u" udp_len="%u" udp_csum="%u" udp_payload="%s" """
        st = st % (self.sport, self.dport, self.length, self.checksum, hexlify(self._payload))

        return st

TCP包类
TCP格式

            0                   1                   2                   3   
            0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |          Source Port          |       Destination Port        |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |                        Sequence Number                        |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |                    Acknowledgment Number                      |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |  Data |           |U|A|P|R|S|F|                               |
           | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
           |       |           |G|K|H|T|N|N|                               |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |           Checksum            |         Urgent Pointer        |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |                    Options                    |    Padding    |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |                             data                              |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

初始化函数: 数据中的TCP头可能是假的,必通过正则及匹配判断所有字段都是正确的或没有解码选项

def __init__(self,data):
     
        self._data = data
        (self.sport,self.dport, \
        self.seq,self.ack,self.b1,self.b2, \
        self.window,self.checksum,
        self.urgent)=struct.unpack(">HHIIBBHHH",data[0:20])

        
        self.offset = (self.b1 & 0xf0)>>4
        self.res = (self.b1&0xf)|(self.b2&0xc0)<<4

        self.__flags = {1:"C", 2:"E", 4:"U", 8:"A", 16:"P", 32:"R", 64:"S", 128:"F"}
        self.__flags_keys = self.__flags.keys().sort()
        self.flags = (self.b2 & 0x3f)
       
        self.opt =[]
        strlog ="""
            tcp packet
            sport = %s
            dport = %s
            seq = %s
            ack = %s
            b1 = 0x%02x
            b2 = 0x%02x
            offset = %d
        """ % (self.sport,self.dport,self.seq,self.ack,self.b1,self.b2,self.offset)
  
        if self.offset <= 5:
            self.payload = data[20:]

        else:
            optionsize = self.offset*4-20
            

            self.options = data[20:20+optionsize]
            self.payload = data[20+optionsize:]
            self._parseoptions()

str函数,通过正则表达式,匹配对应的字符串

def __str__(self):
        st=""" tcp_sport="%u" tcp_dport="%u" """+\
        """ tcp_seq="%u" tcp_ack="%u" tcp_offset="%u" """+\
        """ tcp_flags="%u"  """+\
        """ tcp_window="%u" tcp_csum="%u" tcp_urgptr="%u" """

        st = st % \
        (self.sport,self.dport,
        self.seq,self.ack,self.b1,self.b2,
        self.window,self.checksum,self.urgent)

        if len(self.opt)>0:
            st_opt = """ tcp_optnum="%u" """ % len(self.opt)
            i=0

            for (c,l,v)  in self.opt:
                st_opt = st_opt + \
                """ tcp_optcode="%u" tcp_optlen="%u" tcp_optpayload="%s" """

                st_opt = st_opt % \
                (c,l,hexlify(v))

                i = i+1

        else:
            st_opt=""

        st = st+st_opt+""" tcp_payload="%s" """ % hexlify(self.payload)

        return st

解析选项函数,传入self参数,其中的options是核心,c判断是否处理更多选项,处理则将参数放入opt对象中,若无参数传入则报错

   def _parseoptions(self):
        options = self.options[:]
       
        while len(options)>0:
            c, = struct.unpack(">B",options[0])

            if c==0:
                self.opt.append((0,0,""))
                return 

            elif c==1:
                self.opt.append((1,0,""))
                options=options[1:]

            else:
                try:
                    l, = struct.unpack(">B",options[1:2])
                    l = l - 2
                    if(l > (len(options)-2)):
                        logger.warning("Can't decode TCP option %02x: Payload:%s " % (c, hexlify(self.options)))
                        self.offset = 5
                        return
                    
                    if (l>0):
                        v = options[2:2+l]
                        self.opt.append((c,l,v))
                        options=options[2+l:]

                    elif l==0:
                        v=""
                        self.opt.append((c,l,v))
                        options=options[2+l:]

                    else:
                        raise Exception, "Error processing TCP Options"

                except Exception, e_msg:
                    options=options[2:]
                    logger.warning("Can't decode TCP option %02x: Payload:%s (exception: %s)" % (c, hexlify(self.options), str(e_msg)))

转存函数,打印相关信息,通过option长度判断通过option还是payload调用dumpexdata函数

   def dump(self):
        print "TCP Header"
        print "SPORT:%u DPORT:%u" % (self.sport,self.dport)
        print "SEQ:%08x ACK:%08x" % (self.seq,self.ack)
        print "HDRLEN:%04x WINDOW:%04x FLAGS:%s" % (self.offset,self.window,self._getflags())
        print "CHEKSUM:%04x URG:%04x" % (self.checksum,self.urgent)

        if len(self.options)>0:
            print "Options"
            dumphexdata(self.options)

            print "Payload"
            dumphexdata(self.payload)

获取flags函数,获取self对象中flag的key

    def _getflags(self):
        st =""

        for k in self.__flags_keys():
            if self.flags & k:
                st += self.__flags[k]

            else:
                st += "."

        return st

根据socket.IPPROTO的信息返回连接类型

def getprotobynumber(n):
    if n == socket.IPPROTO_ICMP:
        return "ICMP"

    elif n == socket.IPPROTO_UDP:
        return "UDP"

    elif n == socket.IPPROTO_TCP:
        return "TCP"

    else:
        return "UNKNOWN:%u"  % n

RawPacket、UnknownIPPacket类,存储以太网捕获的原始数据包

class RawPacket:	class UnknownIPPacket:
 
    def __init__(self,data):
        self._data = data

转存函数,打印相关信息,调用dumpexdata函数

    def dump(self):
        dumphexdata(self._data)

str函数,通过正则表达式,匹配对应的字符串

    def __str__(self):
        return "raw_payload=\""+hexlify(self._data)+"\""

ICMPPacket类,存储一个ICMP报文

初始化函数,检查数据的长度,因为可能是一个假数据包

def __init__(self,data):
        self._data = data
        (self.type,self.code,self.checksum)= \
                struct.unpack(">BBH",data[0:4])
        if self.type == 0 or self.type == 8:
            (self.icmp_id,self.icmp_seq) = struct.unpack(">HH",data[4:8])
            self.packetpayload = data[8:]

        else:
            self.icmp_id = self.icmp_seq = 0
            self.packetpayload = data[4:]

转存函数,打印相关信息

 def dump(self):
        print "ICMP Header"
        print "TYPE: %02x CODE:%02x CHECKSUM:%04x" % (self.type,self.code,self.checksum)

str函数,通过正则表达式,匹配对应的字符串

  def __str__(self):
        st=""" icmp_type="%u" icmp_code="%u" """+\
            """ icmp_csum="%u" icmp_id="%u" icmp_seq="%u" """ + \
            """ icmp_payload="%s" """

        st = st % (self.type,self.code,self.checksum,self.icmp_id,self.icmp_seq,hexlify(self.packetpayload))

        return st

IPPacket类,存储一个IP数据包

初始化函数,先用包中的数据初始化类,然后解码IP报文

    def __init__(self,data):
 
        self.opt = []

        if len(data)>=20:
            self.packet = data
            (self.version, self.tos, self.length, \
            self.id,self.offset, \
            self.ttl,self.protocol, \
            self.checksum,self.sip, \
            self.dip) = struct.unpack(">BBHHHBBHII",data[0:20])

            self.hdrlen = (self.version & 0xf)
            self.version = (self.version & 0xf0)>>4

            if self.hdrlen == 5:
                self.options=""
                self.payload=data[20:20+self.length]

            else:
                lenopt = self.hdrlen*4-20
                print "Opciones: %u " % lenopt
                self.options=data[20:20+lenopt]
                self._parseoptions()
                self.payload=data[20+lenopt:]

            if len(self.payload)>0:
                if self.protocol == socket.IPPROTO_UDP:
                    self.packetpayload = UDPPacket(self.payload)
                    self.dport = self.packetpayload.dport
                    self.sport = self.packetpayload.dport

                elif self.protocol == socket.IPPROTO_TCP:
                    self.packetpayload = TCPPacket(self.payload)
                    self.dport = self.packetpayload.dport
                    self.sport = self.packetpayload.sport

                elif self.protocol == socket.IPPROTO_ICMP:
                    self.packetpayload = ICMPPacket(self.payload)
                    self.dport = self.sport = 0

                else:
                    self.packetpayload = UnknownIPPacket(self.payload)
                    self.dport = self.sport = 0

            else:
                self.packetpayload = ""

        else:
            raise Exception,"Error: Incomplete ip packet"

str函数,通过正则表达式,匹配对应的字符串

  def __str__(self):
        st = """ip_ver="%u" ip_hdrlen="%u" ip_tos="%u" """ + \
             """ip_len="%u" ip_id="%u" """ + \
             """ip_offset="%u" """ + \
             """ip_ttl="%u" ip_proto="%u" """ + \
             """ip_csum="%u" """ + \
             """ip_src="%s" ip_dst="%s" """

        st = st % \
                (self.version,self.hdrlen,self.tos,
                self.length,self.id,
                self.offset,
                self.ttl,self.protocol,
                self.checksum,socket.inet_ntoa(struct.pack(">L",self.sip)),
                socket.inet_ntoa(struct.pack(">L",self.dip)))

        if len(self.opt)>0:
            st_opt=""" ip_optnum="%u" """ % len(self.opt)

            for (c,l,v) in self.opt:
                print c,l,v
                st_opt = st_opt + \
                    """ip_optcode="%u" ip_optlen="%u" ip_optpayload="%s" """ % \
                    (c,l,hexlify(v))

        else:
            st_opt=""

        if self.packetpayload<>"":
         
            st = st+st_opt+str(self.packetpayload)

        else:
            st = st+st_opt

        return st

转存函数,先转存ip包,然后打印选项

def dump(self):

        print "IP Header"
        print "Version:%02x hdrlen:%02x tos:%02x packetlen:%04x" % (self.version,self.hdrlen,self.tos,self.length)
        print "ID:%04x Flags:%02x FragOffset:%04x" % (self.id,self.flags,self.offset)
        print "TTL:%02x Protocol:%s Checksum:%04x" % (self.ttl,getprotobynumber(self.protocol),self.checksum)
        print "SRC:%s DST:%s" % (socket.inet_ntoa(struct.pack("L",socket.htonl(self.sip))), \
            socket.inet_ntoa(struct.pack("L",socket.htonl(self.dip))))
       
        if len(self.options)>0:
            print "Dump IP options:"
            dumphexdata(self.options)

        if self.packetpayload!=None:
            self.packetpayload.dump()

IPV6Packet类,存储一个IPv6数据包

IPv6数据包格式

 Oct     byte 1            byte2            byte 3            byte 4
        |________________|________________|________________|________________|
      0 |version| class(8)        |      Flow label(20b)                    |
      4 |payload len                      | next header    | hop limit      |
      8 |_______________________src addr (128bits)__________________________|
      12|___________________________________________________________________|
      16|___________________________________________________________________|
      20|___________________________________________________________________|
      24|_______________________dest addr (128 bits)________________________|
      28|___________________________________________________________________|
      32|___________________________________________________________________|
      36|___________________________________________________________________| 

初始化函数,首先用包中的数据初始化类,然后指定下一个报头的类型

 def __init__(self,data):
 
        self.opt = []    
        if len(data)>=40:
            vlc,pack_length,next_header_type,hop_lmt = struct.unpack("!IHBB",data[0:8])    
            self.src_ip = socket.inet_ntop(socket.AF_INET6,data[8:24])
            self.dst_ip = socket.inet_ntop(socket.AF_INET6,data[24:40])            
            version = vlc >> 28
            traffic_class = (vlc & 0x0ff00000) >> 20
            label = (vlc & 0x000fffff)
            header_len = 40
            data_size = len(data)
            self.packet = data 
            self.version = version
            self.traffic_class = traffic_class
            self.flow_label = label
            self.payload_len = pack_length
            self.hop_limit = hop_lmt
            self.protocol = next_header_type
            self.payload = data[40:40+self.payload_len]
            if pack_length> 0:
                if self.protocol == socket.IPPROTO_ICMP:
                    self.packetpayload = ICMPPacket(self.payload)
                    self.dport = 0
                if self.protocol == socket.IPPROTO_TCP:
                    self.packetpayload = TCPPacket(self.payload)
                    self.dport = self.packetpayload.dport
                    self.sport = self.packetpayload.sport
                if self.protocol == socket.IPPROTO_UDP:
                    self.packetpayload = UDPPacket(self.payload)
                    self.dport = self.packetpayload.dport
                    self.sport = self.packetpayload.dport

            else:
                logger.info("Unknown packet type:%s" % self.protocol)
                self.packetpayload = ""

        else:
            raise Exception,"Error: Incomplete ip packet"

    def __str__(self):
        st = """ip_ver="%u" ip_traffic="%u" ip_flowlabel="%u" """ + \
             """ip_payload_len="%u" ip_proto="%u" """ + \
             """ip_hoplimit="%u" ip_src="%s" ip_dst="%s"  """
        st = st % \
                (self.version, \
                 self.traffic_class, \
                 self.flow_label, \
                 self.payload_len, \
                 self.protocol, \
                 self.hop_limit, \
                 self.src_ip, \
                 self.dst_ip
                 )

        if self.packetpayload <> "":
         
            st = st + str(self.packetpayload)
        return st

存储ip包函数

    def dump(self):
        print "IP Header"
        print "Version:0x%x traffic_class:0x%02x flow_label:0x%03x" % (self.version, self.traffic_class, self.flow_label)
        print "payload_len:0x%04x next_header:0x%02x hop_limit:0x%02x" % (self.packet_len, self.protocol, self.hop_limit)
        print "SRC:%s DST:%s" % (self.src_ip, self.dst_ip)

        if len(self.options) > 0:
            print "Dump IP options:"
            dumphexdata(self.options)
        if self.packetpayload != None:
            self.packetpayload.dump()


 类似资料: