def decode(self): # Decode the data nla.decode(self) # Calculate offset of the segs offset = self.offset + 16 # Point the addresses addresses = self.data[offset:] # Extract the number of segs n_segs = self['segments_left'] + 1 # Init segs segs = [] # Move 128 bit in each step for i in range(n_segs): # Save the segment segs.append(inet_ntop(AF_INET6, addresses[i * 16:i * 16 + 16])) # Save segs self['segs'] = segs # Init tlvs self['tlvs'] = '' # If hmac is used if self.has_hmac(): # Point to the start of hmac hmac = addresses[n_segs * 16:n_segs * 16 + 40] # Save tlvs section self['tlvs'] = hexdump(hmac) # Show also the hmac key self['hmac'] = hexdump(hmac[4:8])
def decode(self): # Decode the data nla.decode(self) # Extract the encap mode self['mode'] = (self.r_encapmodes .get(self['encapmode'], "encap")) # Calculate offset of the segs offset = self.offset + 16 # Point the addresses addresses = self.data[offset:] # Extract the number of segs n_segs = self['segments_left'] + 1 # Init segs segs = [] # Move 128 bit in each step for i in range(n_segs): # Save the segment segs.append(inet_ntop(AF_INET6, addresses[i * 16:i * 16 + 16])) # Save segs self['segs'] = segs # Init tlvs self['tlvs'] = '' # If hmac is used if self.has_hmac(): # Point to the start of hmac hmac = addresses[n_segs * 16:n_segs * 16 + 40] # Save tlvs section self['tlvs'] = hexdump(hmac) # Show also the hmac key self['hmac'] = hexdump(hmac[4:8])
def decode_nlas(self): ''' Decode the NLA chain. Should not be called manually, since it is called from `decode()` routine. ''' while self.buf.tell() < (self.offset + self.length): init = self.buf.tell() nla = None # pick the length and the type (length, msg_type) = struct.unpack('HH', self.buf.read(4)) # first two bits of msg_type are flags: msg_type = msg_type & ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) # rewind to the beginning self.buf.seek(init) length = min(max(length, 4), (self.length - self.buf.tell() + self.offset)) # we have a mapping for this NLA if msg_type in self.t_nla_map: # get the class msg_class = self.t_nla_map[msg_type][0] # is it a class or a function? if isinstance(msg_class, types.MethodType): # if it is a function -- use it to get the class msg_class = msg_class(buf=self.buf, length=length) # and the name msg_name = self.t_nla_map[msg_type][1] # is it an array? msg_array = self.t_nla_map[msg_type][3] # initstring msg_init = self.t_nla_map[msg_type][4] # decode NLA nla = msg_class(self.buf, length, self, debug=self.debug, init=msg_init) nla.nla_array = msg_array try: nla.decode() nla.nla_flags = msg_type & (NLA_F_NESTED | NLA_F_NET_BYTEORDER) except Exception: logging.warning("decoding %s" % (msg_name)) logging.warning(traceback.format_exc()) self.buf.seek(init) msg_name = 'UNDECODED' msg_value = hexdump(self.buf.read(length)) else: msg_value = nla.getvalue() else: msg_name = 'UNKNOWN' msg_value = hexdump(self.buf.read(length)) self['attrs'].append([msg_name, msg_value]) # fix the offset self.buf.seek(init + self.msg_align(length))
def decode_nlas(self): ''' Decode the NLA chain. Should not be called manually, since it is called from `decode()` routine. ''' while self.buf.tell() < (self.offset + self.length): init = self.buf.tell() nla = None # pick the length and the type (length, msg_type) = struct.unpack('HH', self.buf.read(4)) # first two bits of msg_type are flags: msg_type = msg_type & ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) # rewind to the beginning self.buf.seek(init) length = min(max(length, 4), (self.length - self.buf.tell() + self.offset)) # we have a mapping for this NLA if msg_type in self.t_nla_map: # get the class msg_class = self.t_nla_map[msg_type][0] # is it a class or a function? if isinstance(msg_class, types.MethodType): # if it is a function -- use it to get the class msg_class = msg_class(buf=self.buf, length=length) # and the name msg_name = self.t_nla_map[msg_type][1] # is it an array? msg_array = self.t_nla_map[msg_type][3] # initstring msg_init = self.t_nla_map[msg_type][4] # decode NLA nla = msg_class(self.buf, length, self, debug=self.debug, init=msg_init) nla.nla_array = msg_array try: nla.decode() nla.nla_flags = msg_type & (NLA_F_NESTED | NLA_F_NET_BYTEORDER) except Exception: logging.warning("decoding %s" % (msg_name)) logging.warning(traceback.format_exc()) self.buf.seek(init) msg_name = 'UNDECODED' msg_value = hexdump(self.buf.read(length)) else: msg_value = nla.getvalue() else: msg_name = 'UNKNOWN' msg_value = hexdump(self.buf.read(length)) self['attrs'].append([msg_name, msg_value]) # fix the offset self.buf.seek(init + NLMSG_ALIGN(length))
def test_hexdump(self): binary = b'abcdef5678' dump1 = hexdump(binary) dump2 = hexdump(binary, length=6) assert len(dump1) == 29 assert len(dump2) == 17 assert dump1[2] == \ dump1[-3] == \ dump2[2] == \ dump2[-3] == ':' assert hexload(dump1) == binary assert hexload(dump2) == binary[:6]
def decode_nlas(self): while self.buf.tell() < (self.offset + self.length): init = self.buf.tell() # pick the length and the type (length, msg_type) = struct.unpack('HH', self.buf.read(4)) # rewind to the beginning self.buf.seek(init) length = min(max(length, 4), (self.length - self.buf.tell() + self.offset)) # we have a mapping for this NLA if msg_type in self.t_nla_map: # get the class msg_class = self.t_nla_map[msg_type][0] # and the name msg_name = self.t_nla_map[msg_type][1] try: # decode NLA nla = msg_class(self.buf, length, self) nla.decode() self['attrs'].append((msg_name, nla.getvalue())) except: # FIXME import traceback traceback.print_exc() self.buf.seek(init) self['attrs'].append((msg_name, hexdump(self.buf.read(length)))) # fix the offset self.buf.seek(init + NLMSG_ALIGN(length))
def save(scan_dump, dumpfilename): # I can save an entire dump in one file! # The scan_dump is an array but each element holds a ref to the blob and an # offset into the blob. So just need to save the blob. with open(dumpfilename, "w") as outfile: print(hexdump(scan_dump[0].data), file=outfile) with open(dumpfilename + ".bin", "wb") as outfile: outfile.write(scan_dump[0].data)
def decode(self): nla.decode(self) family = struct.unpack('H', self['value'][:2])[0] addr = self['value'][2:] if len(addr): if (family == AF_INET and len(addr) == 4) or \ (family == AF_INET6 and len(addr) == 16): addr = inet_ntop(family, addr) else: addr = hexdump(addr) self.value = {'family': family, 'addr': addr}
def decode(self): # raw bytes s = self.format_oui(self.data[0:3]) try: vendor = oui.vendor_lookup(s.upper()) except KeyError: vendor = "Unknown" self.value.update({ "OUI": s, "vendor name": vendor, "_raw": self.data, "hex": hexdump(self.data) })
def decode(self): ( count, period, bitmapc, ) = struct.unpack('BBB', self.data[0:3]) bitmap_hex = hexdump(self.data[3:]) self.value.update({ "DTIM Count": count, "DTIM Period": period, "Bitmap Control": bitmapc, "Bitmap": bitmap_hex })
def binary_vendor(self, rawdata): ''' Extract vendor data ''' vendor = {} # pdb.set_trace() size = len(rawdata) # if len > 4 and rawdata[0] == ms_oui[0] # and rawdata[1] == ms_oui[1] and rawdata[2] == ms_oui[2] if size < 3: vendor["VENDOR_NAME"] = "Vendor specific: <too short data:" +hexdump(rawdata) return vendor
def binary_vendor(self, rawdata): ''' Extract vendor data ''' vendor = {} # pdb.set_trace() size = len(rawdata) # if len > 4 and rawdata[0] == ms_oui[0] # and rawdata[1] == ms_oui[1] and rawdata[2] == ms_oui[2] if size < 3: vendor["VENDOR_NAME"] = "Vendor specific: <too short data:" + hexdump(rawdata) return vendor
def __init__(self, data): # data is the buffer # Caller is responsible for parsing: # id: octet # len: octet # data: octet(s) <-- we get this # and sending us the data self.data = data # Decode into a dict of key/value pairs. Using 80211_2016.pdf names as # closely as possible. Keys with leading '_' are extra useful information. # self.value = { "_ID": self.ID, "_hex": hexdump(self.data), "_raw": self.data }
def decode_nlas(self): while self.buf.tell() < (self.offset + self.length): init = self.buf.tell() # pick the length and the type (length, msg_type) = struct.unpack('HH', self.buf.read(4)) # rewind to the beginning self.buf.seek(init) length = min(max(length, 4), (self.length - self.buf.tell() + self.offset)) # we have a mapping for this NLA if msg_type in self.t_nla_map: # get the class msg_class = self.t_nla_map[msg_type][0] # is it a class or a function? if isinstance(msg_class, types.MethodType): # if it is a function -- use it to get the class msg_class = msg_class(buf=self.buf, length=length) # and the name msg_name = self.t_nla_map[msg_type][1] # decode NLA nla = msg_class(self.buf, length, self, debug=self.debug) try: nla.decode() except: # FIXME self.buf.seek(init) msg_value = hexdump(self.buf.read(length)) else: msg_value = nla.getvalue() if self.debug: self['attrs'].append([msg_name, msg_value, msg_type, length, init]) else: self['attrs'].append([msg_name, msg_value]) # fix the offset self.buf.seek(init + NLMSG_ALIGN(length))
def test_ssid(): # check for evil ssid decoding import struct evil_ssid = ("hello, world", "", "\x00\x00\x00\x00\x00\x00", "(╯°□°)╯︵ ┻━┻", "01234567890123456789012345678901") for ssid in evil_ssid: print(len(ssid), ssid) buf = bytes(ssid, "utf8") print(buf) ie_id = 1 data = struct.pack("%ds" % len(buf), buf) ssid_ie = nl80211.SSID(data) ssid_ie.decode() new_ssid = ssid_ie.pretty_print() print(len(new_ssid), new_ssid) assert len(ssid) == len(new_ssid), (len(ssid), len(new_ssid)) assert ssid == new_ssid, (hexdump(buf), ssid_ie.fields.value)
def decode(self): # Be VERY careful with the SSID. Can contain hostile input. # SQL injection. Terminal characters. HTML injection. XSS. etc. fmt = '%is' % len(self.data) ssid = struct.unpack(fmt, self.data)[0] self.value.update({"_raw": ssid, "_hex": hexdump(self.data)}) # TODO utf8 encoding of SSID is optional. Shouldn't be unconditionally # treating as UTF8 # try: s = self.value["_raw"].decode("utf8") # TODO check for unprintable chars (how badly will this hose unicode????) except UnicodeDecodeError: msg = "(error! SSID is invalid unicode) " + self.value["_hex"] log.error(msg) s = "<invalid utf8>" self.value["SSID"] = s
def decode_nlas(self): ''' Decode the NLA chain. Should not be called manually, since it is called from `decode()` routine. ''' while self.buf.tell() < (self.offset + self.length): init = self.buf.tell() nla = None # pick the length and the type (length, msg_type) = struct.unpack('HH', self.buf.read(4)) # rewind to the beginning self.buf.seek(init) length = min(max(length, 4), (self.length - self.buf.tell() + self.offset)) # we have a mapping for this NLA if msg_type in self.t_nla_map: # get the class msg_class = self.t_nla_map[msg_type][0] # is it a class or a function? if isinstance(msg_class, types.MethodType): # if it is a function -- use it to get the class msg_class = msg_class(buf=self.buf, length=length) # and the name msg_name = self.t_nla_map[msg_type][1] # decode NLA nla = msg_class(self.buf, length, self, debug=self.debug) try: nla.decode() except: # FIXME self.buf.seek(init) msg_name = 'UNKNOWN' msg_value = hexdump(self.buf.read(length)) else: msg_value = nla.getvalue() self['attrs'].append([msg_name, msg_value]) # fix the offset self.buf.seek(init + NLMSG_ALIGN(length))
Module is a name within rtnl hierarchy. File should be a binary data in the escaped string format (see samples). ''' import sys from pprint import pprint from importlib import import_module from pyroute2.common import load_dump from pyroute2.common import hexdump mod = sys.argv[1] mod = mod.replace('/', '.') f = open(sys.argv[2], 'r') s = mod.split('.') package = '.'.join(s[:-1]) module = s[-1] m = import_module(package) met = getattr(m, module) data = load_dump(f) offset = 0 inbox = [] while offset < len(data): msg = met(data[offset:]) msg.decode() print(hexdump(msg.data)) pprint(msg) print('.' * 40) offset += msg['header']['length']
def decode(self): nla_base.decode(self) self.value = hexdump(self["value"])
''' Simple taskstats sample. Usage: python taskstats.py [pid] ''' import os import sys from pyroute2 import TaskStats from pyroute2.common import hexdump pid = sys.argv[-1] if len(sys.argv) > 1 else os.getpid() ts = TaskStats() ret = ts.get_pid_stat(int(pid))[0] # raw hex structure to check alignment print(hexdump(ret.raw)) # parsed structure print(ret)
def decode(self): nla_base.decode(self) self.value = hexdump(self['value'])
def decode(self): rt_slot.decode(self) length = self['header']['length'] self['value'] = hexdump(self.data[self.offset + 2:self.offset + length])
''' Monitor process exit ''' from pyroute2 import TaskStats from pyroute2.common import hexdump pmask = '' with open('/proc/cpuinfo', 'r') as f: for line in f.readlines(): if line.startswith('processor'): pmask += ',' + line.split()[2] pmask = pmask[1:] ts = TaskStats() ts.register_mask(pmask) msg = ts.get()[0] print(hexdump(msg.raw)) print(msg) ts.deregister_mask(pmask) ts.release()
Module is a name within rtnl hierarchy. File should be a binary data in the escaped string format (see samples). ''' import sys from pprint import pprint from importlib import import_module from pyroute2.common import load_dump from pyroute2.common import hexdump mod = sys.argv[1] mod = mod.replace('/', '.') f = open(sys.argv[2], 'r') s = mod.split('.') package = '.'.join(s[:-1]) module = s[-1] m = import_module(package) met = getattr(m, module) data = load_dump(f) offset = 0 inbox = [] while offset < len(data): msg = met(data[offset:]) msg.decode() print(hexdump(msg.buf.getvalue())) pprint(msg) print('.'*40) offset += msg['header']['length']
''' Simple taskstats sample. ''' import os from pyroute2 import TaskStats from pyroute2.common import hexdump pid = os.getpid() ts = TaskStats() # bind is required in the case of generic netlink ts.bind() ret = ts.get_pid_stat(int(pid))[0] # raw hex structure to check alignment print(hexdump(ret.raw)) # parsed structure print(ret) ts.close()
def decode_nlas(self): ''' Decode the NLA chain. Should not be called manually, since it is called from `decode()` routine. ''' while self.buf.tell() < (self.offset + self.length): init = self.buf.tell() nla = None # pick the length and the type try: (length, msg_type) = struct.unpack('HH', self.buf.read(4)) except Exception: # another alignment trick if self.buf.tell() == (self.offset + self.length): break # first two bits of msg_type are flags: msg_type = msg_type & ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) # rewind to the beginning self.buf.seek(init) length = min(max(length, 4), (self.length - self.buf.tell() + self.offset)) if length < 4: # alignment trick self.buf.seek(init + length) continue # we have a mapping for this NLA if msg_type in self.t_nla_map: prime = self.t_nla_map[msg_type] # get the class msg_class = self.t_nla_map[msg_type]['class'] # is it a class or a function? if isinstance(msg_class, types.FunctionType): # if it is a function -- use it to get the class msg_class = msg_class(self, buf=self.buf, length=length) # decode NLA nla = msg_class(self.buf, length, self, debug=self.debug, init=prime['init']) nla.nla_array = prime['nla_array'] try: nla.decode() nla.nla_flags = msg_type & (NLA_F_NESTED | NLA_F_NET_BYTEORDER) msg_name = prime['name'] except Exception: logging.warning("decoding %s" % (prime['name'])) logging.warning(traceback.format_exc()) self.buf.seek(init) msg_name = 'UNDECODED' msg_value = hexdump(self.buf.read(length)) else: msg_value = nla.getvalue() else: msg_name = 'UNKNOWN' msg_value = hexdump(self.buf.read(length)) self['attrs'].append([msg_name, msg_value]) # fix the offset self.buf.seek(init + self.msg_align(length))
def decode(self): self.offset = self.buf.tell() # decode the header if self.header is not None: try: self['header'].decode() # update length from header # it can not be less than 4 self.length = max(self['header']['length'], 4) save = self.buf.tell() self.buf.seek(self.offset) self.raw = self.buf.read(self.length) self.buf.seek(save) if self.debug: self['header']['class'] = self.__class__.__name__ self['header']['raw'] = hexdump(self.raw) self['header']['offset'] = self.offset self['header']['length'] = self.length except Exception as e: raise NetlinkHeaderDecodeError(e) # decode the data try: if self.pack == 'struct': names = [] formats = [] for field in self.fields: names.append(field[0]) formats.append(field[1]) fields = ((','.join(names), ''.join(formats)), ) else: fields = self.fields for field in fields: name = field[0] fmt = field[1] # 's' and 'z' can be used only in connection with # length, encoded in the header if field[1] in ('s', 'z'): fmt = '%is' % (self.length - 4) size = struct.calcsize(fmt) raw = self.buf.read(size) actual_size = len(raw) # FIXME: adjust string size again if field[1] in ('s', 'z'): size = actual_size fmt = '%is' % (actual_size) if size == actual_size: value = struct.unpack(fmt, raw) if len(value) == 1: self[name] = value[0] # cut zero-byte from z-strings # 0x00 -- python3; '\0' -- python2 if field[1] == 'z' and self[name][-1] in (0x00, '\0'): self[name] = self[name][:-1] else: self[name] = value else: # FIXME: log an error pass except Exception as e: raise NetlinkDataDecodeError(e) # decode NLA try: # align NLA chain start self.buf.seek(NLMSG_ALIGN(self.buf.tell())) # read NLA chain if self.nla_map: self.decode_nlas() except Exception as e: raise NetlinkNLADecodeError(e) if len(self['attrs']) == 0: del self['attrs'] if self['value'] is NotInitialized: del self['value']
Module is a name within rtnl hierarchy. File should be a binary data in the escaped string format (see samples). ''' import sys from pprint import pprint from importlib import import_module from pyroute2.common import load_dump from pyroute2.common import hexdump mod = sys.argv[1] f = open(sys.argv[2], 'r') s = mod.split('.') package = '.'.join(s[:-1]) module = s[-1] m = import_module(package) met = getattr(m, module) data = load_dump(f) offset = 0 inbox = [] while offset < len(data): msg = met(data[offset:]) msg.decode() print(hexdump(msg.raw)) pprint(msg) print('.'*40) offset += msg['header']['length']
./decoder.py pyroute2.netlink.rtnl.tcmsg.tcmsg ./sample_packet_01.data ./decoder.py pyroute2.netlink.nl80211.nl80211cmd ./nl80211.data Module is a name within rtnl hierarchy. File should be a binary data in the escaped string format (see samples). ''' import sys from io import StringIO from pprint import pprint from importlib import import_module from pyroute2.common import load_dump from pyroute2.common import hexdump from pyroute2.netlink.generic.wireguard import wgmsg as met if __name__ == "__main__": with open(sys.argv[1], 'r') as f: for line in f.readlines(): try: data = load_dump(StringIO(line)) offset = 0 inbox = [] while offset < len(data): msg = met(data[offset:]) msg.decode() print(hexdump(msg.data)) pprint(msg) print('.' * 40) offset += msg['header']['length'] except Exception as e: pprint(e)
def decode(self): rt_slot.decode(self) length = self['header']['length'] self['value'] = hexdump(self.data[self.offset + 2: self.offset + length])