def in6_getRandomizedIfaceId(ifaceid, previous=None): """ Implements the interface ID generation algorithm described in RFC 3041. The function takes the Modified EUI-64 interface identifier generated as described in RFC 4291 and an optional previous history value (the first element of the output of this function). If no previous interface identifier is provided, a random one is generated. The function returns a tuple containing the randomized interface identifier and the history value (for possible future use). Input and output values are provided in a "printable" format as depicted below. ex: >>> in6_getRandomizedIfaceId('20b:93ff:feeb:2d3') ('4c61:76ff:f46a:a5f3', 'd006:d540:db11:b092') >>> in6_getRandomizedIfaceId('20b:93ff:feeb:2d3', previous='d006:d540:db11:b092') ('fe97:46fe:9871:bd38', 'eeed:d79c:2e3f:62e') """ s = b"" if previous is None: d = b"".join(chb(x) for x in range(256)) for _ in range(8): s += chb(random.choice(d)) previous = s s = inet_pton(socket.AF_INET6, "::" + ifaceid)[8:] + previous import hashlib s = hashlib.md5(s).digest() s1, s2 = s[:8], s[8:] s1 = chb(orb(s1[0]) | 0x04) + s1[1:] s1 = inet_ntop(socket.AF_INET6, b"\xff" * 8 + s1)[20:] s2 = inet_ntop(socket.AF_INET6, b"\xff" * 8 + s2)[20:] return (s1, s2)
def diffplot(self, f, delay=1, lfilter=None, **kargs): """diffplot(f, delay=1, lfilter=None) Applies a function to couples (l[i],l[i+delay]) A list of matplotlib.lines.Line2D is returned. """ # Get the list of packets if lfilter is None: l = [f(self.res[i], self.res[i + 1]) for i in range(len(self.res) - delay)] else: l = [f(self.res[i], self.res[i + 1]) for i in range(len(self.res) - delay) if lfilter(self.res[i])] # Mimic the default gnuplot output if kargs == {}: kargs = MATPLOTLIB_DEFAULT_PLOT_KARGS lines = plt.plot(l, **kargs) # Call show() if matplotlib is not inlined if not MATPLOTLIB_INLINED: plt.show() return lines
def pretty_routes(rtlst, header, sortBy=0): """Pretty route list, and add header""" _l_header = len(header[0]) _space = " " # Sort correctly rtlst.sort(key=lambda x: x[sortBy]) # Append tag rtlst = header + rtlst # Detect column's width colwidth = [max([len(y) for y in x]) for x in apply(zip, rtlst)] # Make text fit in box (if exist) # TODO: find a better and more precise way of doing this. That's currently working but very complicated width = get_terminal_width() if width: if sum(colwidth) > width: # Needs to be cropped _med = (width // _l_header) - (1 if WINDOWS else 0) # Windows has a fat window border # Crop biggest until size is correct for i in range(1, len(colwidth)): # Should use while, but this is safer if (sum(colwidth)+6) <= width: break _max = max(colwidth) colwidth = [_med if x == _max else x for x in colwidth] def _crop(x, width): _r = x[:width] if _r != x: _r = x[:width-3] return _r + "..." return _r rtlst = [tuple([_crop(rtlst[j][i], colwidth[i]) for i in range(0, len(rtlst[j]))]) for j in range(0, len(rtlst))] # Recalculate column's width colwidth = [max([len(y) for y in x]) for x in apply(zip, rtlst)] fmt = _space.join(["%%-%ds"%x for x in colwidth]) rt = "\n".join([fmt % x for x in rtlst]) return rt
def RRlist2bitmap(lst): """ Encode a list of integers representing Resource Records to a bitmap field used in the NSEC Resource Record. """ # RFC 4034, 4.1.2. The Type Bit Maps Field import math bitmap = "" lst = sorted(set(lst)) lst = [abs(x) for x in lst if x <= 65535] # number of window blocks max_window_blocks = int(math.ceil(lst[-1] / 256.)) min_window_blocks = int(math.floor(lst[0] / 256.)) if min_window_blocks == max_window_blocks: max_window_blocks += 1 for wb in range(min_window_blocks, max_window_blocks+1): # First, filter out RR not encoded in the current window block # i.e. keep everything between 256*wb <= 256*(wb+1) rrlist = sorted(x for x in lst if 256 * wb <= x < 256 * (wb + 1)) if rrlist == []: continue # Compute the number of bytes used to store the bitmap if rrlist[-1] == 0: # only one element in the list bytes_count = 1 else: max = rrlist[-1] - 256*wb bytes_count = int(math.ceil(max / 8)) + 1 # use at least 1 byte if bytes_count > 32: # Don't encode more than 256 bits / values bytes_count = 32 bitmap += struct.pack("B", wb) bitmap += struct.pack("B", bytes_count) # Generate the bitmap # The idea is to remove out of range Resource Records with these steps # 1. rescale to fit into 8 bits # 2. x gives the bit position ; compute the corresponding value # 3. sum everything bitmap += b"".join( struct.pack( b"B", sum(2 ** (7 - (x - 256 * wb) + (tmp * 8)) for x in rrlist if 256 * wb + 8 * tmp <= x < 256 * wb + 8 * tmp + 8), ) for tmp in range(bytes_count) ) return bitmap
def colgen(*lstcol,**kargs): """Returns a generator that mixes provided quantities forever trans: a function to convert the three arguments into a color. lambda x,y,z:(x,y,z) by default""" if len(lstcol) < 2: lstcol *= 2 trans = kargs.get("trans", lambda x,y,z: (x,y,z)) while True: for i in range(len(lstcol)): for j in range(len(lstcol)): for k in range(len(lstcol)): if i != j or j != k or k != i: yield trans(lstcol[(i+j)%len(lstcol)],lstcol[(j+k)%len(lstcol)],lstcol[(k+i)%len(lstcol)])
def _fix(self, n=0): o = random.choice(self.objlist) if issubclass(o, ASN1_INTEGER): return o(int(random.gauss(0,1000))) elif issubclass(o, ASN1_IPADDRESS): z = RandIP()._fix() return o(z) elif issubclass(o, ASN1_STRING): z = int(random.expovariate(0.05)+1) return o("".join(random.choice(self.chars) for _ in range(z))) elif issubclass(o, ASN1_SEQUENCE) and (n < 10): z = int(random.expovariate(0.08)+1) return o([self.__class__(objlist=self.objlist)._fix(n + 1) for _ in range(z)]) return ASN1_INTEGER(int(random.gauss(0,1000)))
def _fix(self): if self.fmt is None: return ".".join(str(self.idnum) for _ in range(1 + self.depth)) else: oid = [] for i in self.fmt: if i == "*": oid.append(str(self.idnum)) elif i == "**": oid += [str(self.idnum) for i in range(1 + self.depth)] elif isinstance(i, tuple): oid.append(str(random.randrange(*i))) else: oid.append(i) return ".".join(oid)
def find_data(packets): """Analyse a packet list to extract data offsets from packets data.""" # a dictionary to count data offsets (ie != 0x80) # It's formatted: {(src, dst): (total, [count for offset in len])} heuristic = {} # Counts possible data locations # 0x80 are mainly IOxS and trailling 0x00s are just padding for pkt in packets: if PNIORealTime in pkt: pdu = bytes(pkt[PNIORealTime])[:-4].rstrip(b"\0") if (pkt.src, pkt.dst) not in heuristic: heuristic[(pkt.src, pkt.dst)] = (0, []) total, counts = heuristic[(pkt.src, pkt.dst)] if len(counts) < len(pdu): counts.extend([0 for _ in range(len(pdu) - len(counts))]) for i in range(len(pdu)): if orb(pdu[i]) != 0x80: counts[i] += 1 comm = (pkt.src, pkt.dst) heuristic[comm] = (total + 1, counts) # Determine data locations locations = {} for comm in heuristic: total, counts = heuristic[comm] length = len(counts) loc = locations[comm] = [] start = None for i in range(length): if counts[i] > total // 2: # Data if more than half is != 0x80 # noqa: E501 if start is None: start = i else: if start is not None: loc.append(( start - length, PNIORealTimeRawData, {"length": i - start} )) start = None return locations
def analyse_one_profisafe_location(location, entropy): """Analyse one PNIO RTC data location to find if its a PROFISafe :param location: location to analyse, a tuple (start, type, config) :param entropy: the entropy of each byte of the packet data :returns: the configuration associated with the data """ start, klass, conf = location if conf["length"] >= 4: # Minimal PROFISafe length succ_count = 0 for j in range(start, start + conf["length"]): # Limit for a CRC is set to 6 bit of entropy min if j in entropy and entropy[j] >= 6: succ_count += 1 else: succ_count = 0 # PROFISafe profiles must end with at least 3 bytes of high entropy if succ_count >= 3: # Possible profisafe CRC return ( start, Profisafe, {"CRC": succ_count, "length": conf["length"]} ) # Not a PROFISafe profile return (start, klass, conf)
def analyse_profisafe(packets, locations=None): """Analyse a packet list to find possible PROFISafe profils. It's based on an heuristical analysis of each payload to try to find CRC and control/status byte. locations: possible data locations. If not provided, analyse_pn_rt will be called beforehand. If not given, it calls in the same time analyse_data which update the configuration of the data field""" # get data locations and entropy of bytes if not locations: locations = PNIORealTime.find_data(packets) entropies = PNIORealTime.data_entropy(packets, locations) # Try to find at least 3 high entropy successive bytes (the CRC) for comm in entropies: entropy = dict(entropies[comm]) # Convert tuples to key => value for i in range(len(locations[comm])): # update each location with its value after profisafe analysis locations[comm][i] = \ PNIORealTime.analyse_one_profisafe_location( locations[comm][i], entropy ) return locations
def pad(self, esp): """ Add the correct amount of padding so that the data to encrypt is exactly a multiple of the algorithm's block size. Also, make sure that the total ESP packet length is a multiple of 4 bytes. @param esp: an unencrypted _ESPPlain packet @return: an unencrypted _ESPPlain packet with valid padding """ # 2 extra bytes for padlen and nh data_len = len(esp.data) + 2 # according to the RFC4303, section 2.4. Padding (for Encryption) # the size of the ESP payload must be a multiple of 32 bits align = _lcm(self.block_size, 4) # pad for block size esp.padlen = -data_len % align # Still according to the RFC, the default value for padding *MUST* be an # array of bytes starting from 1 to padlen # TODO: Handle padding function according to the encryption algo esp.padding = struct.pack("B" * esp.padlen, *range(1, esp.padlen + 1)) # If the following test fails, it means that this algo does not comply # with the RFC payload_len = len(esp.iv) + len(esp.data) + len(esp.padding) + 2 if payload_len % 4 != 0: raise ValueError('The size of the ESP data is not aligned to 32 bits after padding.') return esp
def _fix(self): nbm = self.multi ip = [] for i, n in enumerate(self.sp): if n == "**": nbm -= 1 remain = 8 - (len(self.sp) - i - 1) - len(ip) + nbm if "" in self.sp: remain += 1 if nbm or self.variable: remain = random.randint(0, remain) for j in range(remain): ip.append("%04x" % random.randint(0, 65535)) elif isinstance(n, RandNum): ip.append("%04x" % n) elif n == 0: ip.append("0") elif not n: ip.append("") else: ip.append("%04x" % n) if len(ip) == 9: ip.remove("") if ip[-1] == "": ip[-1] = "0" return ":".join(ip)
def data_entropy(packets, locations=None): """Analyse a packet list to find the entropy of each data byte locations: possible data locations. If not provided, analyse_pn_rt will be called beforehand. If not given, it calls in the same time analyse_data which update the configuration of the data field""" if not locations: locations = PNIORealTime.find_data(packets) # Retrieve the entropy of each data byte, for each communication entropies = {} for comm in locations: if len(locations[comm]) > 0: # Doesn't append empty data entropies[comm] = [] comm_packets = [] # fetch all packets from the communication for pkt in packets: if PNIORealTime in pkt and (pkt.src, pkt.dst) == comm: comm_packets.append( bytes(pkt[PNIORealTime])[:-4].rstrip(b"\0") ) # Get the entropy for start, dummy, config in locations[comm]: for i in range(start, start + config["length"]): entropies[comm].append( (i, entropy_of_byte(comm_packets, i)) ) return entropies
def attach_filter(fd, iface, bpf_filter_string): """Attach a BPF filter to the BPF file descriptor""" # Retrieve the BPF byte code in decimal command = "%s -i %s -ddd -s 1600 '%s'" % (conf.prog.tcpdump, iface, bpf_filter_string) try: f = os.popen(command) except OSError as msg: raise Scapy_Exception("Failed to execute tcpdump: (%s)" % msg) # Convert the byte code to a BPF program structure lines = f.readlines() if lines == []: raise Scapy_Exception("Got an empty BPF filter from tcpdump !") # Allocate BPF instructions size = int(lines[0]) bpf_insn_a = bpf_insn * size bip = bpf_insn_a() # Fill the BPF instruction structures with the byte code lines = lines[1:] for i in range(len(lines)): values = [int(v) for v in lines[i].split()] bip[i].code = c_ushort(values[0]) bip[i].jt = c_ubyte(values[1]) bip[i].jf = c_ubyte(values[2]) bip[i].k = c_uint(values[3]) # Create the BPF program and assign it to the interface bp = bpf_program(size, bip) ret = LIBC.ioctl(c_int(fd), BIOCSETF, cast(pointer(bp), c_char_p)) if ret < 0: raise Scapy_Exception("Can't attach the BPF filter !")
def _suppress_file_handles_inheritance(r=1000): """HACK: python 2.7 file descriptors. This magic hack fixes https://bugs.python.org/issue19575 and https://github.com/secdev/scapy/issues/1136 by suppressing the HANDLE_FLAG_INHERIT flag to a range of already opened file descriptors. Bug was fixed on python 3.4+ """ if sys.version_info[0:2] >= (3, 4): return [] import stat from msvcrt import get_osfhandle HANDLE_FLAG_INHERIT = 0x00000001 handles = [] for fd in range(r): try: s = os.fstat(fd) except OSError: continue if stat.S_ISREG(s.st_mode): osf_handle = get_osfhandle(fd) flags = wintypes.DWORD() _winapi_GetHandleInformation(osf_handle, flags) if flags.value & HANDLE_FLAG_INHERIT: _winapi_SetHandleInformation(osf_handle, HANDLE_FLAG_INHERIT, 0) # noqa: E501 handles.append(osf_handle) return handles
def p0f_correl(x, y): d = 0 # wwww can be "*" or "%nn". "Tnn" and "Snn" should work fine with # the x[0] == y[0] test. d += (x[0] == y[0] or y[0] == "*" or (y[0][0] == "%" and x[0].isdigit() and (int(x[0]) % int(y[0][1:])) == 0)) # noqa: E501 # ttl d += (y[1] >= x[1] and y[1] - x[1] < 32) for i in [2, 5]: d += (x[i] == y[i] or y[i] == '*') # '*' has a special meaning for ss d += x[3] == y[3] xopt = x[4].split(",") yopt = y[4].split(",") if len(xopt) == len(yopt): same = True for i in range(len(xopt)): if not (xopt[i] == yopt[i] or (len(yopt[i]) == 2 and len(xopt[i]) > 1 and yopt[i][1] == "*" and xopt[i][0] == yopt[i][0]) or (len(yopt[i]) > 2 and len(xopt[i]) > 1 and yopt[i][1] == "%" and xopt[i][0] == yopt[i][0] and int(xopt[i][1:]) % int(yopt[i][2:]) == 0)): same = False break if same: d += len(xopt) return d
def compute_crc(pdu, init=0x555555): def swapbits(a): v = 0 if a & 0x80 != 0: v |= 0x01 if a & 0x40 != 0: v |= 0x02 if a & 0x20 != 0: v |= 0x04 if a & 0x10 != 0: v |= 0x08 if a & 0x08 != 0: v |= 0x10 if a & 0x04 != 0: v |= 0x20 if a & 0x02 != 0: v |= 0x40 if a & 0x01 != 0: v |= 0x80 return v state = swapbits(init & 0xff) + (swapbits((init >> 8) & 0xff) << 8) + (swapbits((init >> 16) & 0xff) << 16) # noqa: E501 lfsr_mask = 0x5a6000 for i in (orb(x) for x in pdu): for j in range(8): next_bit = (state ^ i) & 1 i >>= 1 state >>= 1 if next_bit: state |= 1 << 23 state ^= lfsr_mask return struct.pack("<L", state)[:-1]
def hexdump(x, dump=False): """ Build a tcpdump like hexadecimal view :param x: a Packet :param dump: define if the result must be printed or returned in a variable :returns: a String only when dump=True """ s = "" x = str(x) l = len(x) i = 0 while i < l: s += "%04x " % i for j in range(16): if i+j < l: s += "%02X" % ord(x[i+j]) else: s += " " if j%16 == 7: s += "" s += " " s += sane_color(x[i:i+16]) i += 16 s += "\n" # remove trailing \n if s.endswith("\n"): s = s[:-1] if dump: return s else: print(s)
def getfield(self, pkt, s): if isinstance(s, tuple): s,bn = s else: bn = 0 # we don't want to process all the string nb_bytes = (self.size+bn-1)//8 + 1 w = s[:nb_bytes] # split the substring byte by byte _bytes = struct.unpack('!%dB' % nb_bytes , w) b = 0 for c in range(nb_bytes): b |= int(_bytes[c]) << (nb_bytes-c-1)*8 # get rid of high order bits b &= (1 << (nb_bytes*8-bn)) - 1 # remove low order bits b = b >> (nb_bytes*8 - self.size - bn) if self.rev: b = self.reverse(b) bn += self.size s = s[bn//8:] bn = bn%8 b = self.m2i(pkt, b) if bn: return (s,bn),b else: return s,b
def obfuscate(pay, secret, session_id, version, seq): ''' Obfuscation methodology from section 3.7 https://tools.ietf.org/html/draft-ietf-opsawg-tacacs-06#section-3.7 ''' pad = b"" curr_pad = b"" # pad length must equal the payload to obfuscate. # pad = {MD5_1 [,MD5_2 [ ... ,MD5_n]]} while len(pad) < len(pay): msg = hashlib.md5() msg.update(struct.pack('!I', session_id)) msg.update(secret.encode()) msg.update(struct.pack('!BB', version, seq)) msg.update(curr_pad) curr_pad = msg.digest() pad += curr_pad # Obf/Unobfuscation via XOR operation between plaintext and pad return b"".join(chb(orb(pad[i]) ^ orb(pay[i])) for i in range(len(pay)))
def linehexdump(x, onlyasc=0, onlyhex=0, dump=False): """ Build an equivalent view of hexdump() on a single line Note that setting both onlyasc and onlyhex to 1 results in a empty output :param x: a Packet :param onlyasc: 1 to display only the ascii view :param onlyhex: 1 to display only the hexadecimal view :param dump: print the view if False :returns: a String only when dump=True """ s = "" x = str(x) l = len(x) if not onlyasc: for i in range(l): s += "%02X" % ord(x[i]) if not onlyhex: # separate asc & hex if both are displayed s += " " if not onlyhex: s += sane_color(x) if dump: return s else: print(s)
def whois(ip_address): """Whois client for Python""" whois_ip = str(ip_address) try: query = socket.gethostbyname(whois_ip) except: query = whois_ip s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("whois.ripe.net", 43)) s.send(query + "\r\n") answer = '' while True: d = s.recv(4096) answer += d if not d: break s.close() ignore_tag = "remarks:" # ignore all lines starting with the ignore_tag lines = [ line for line in answer.split("\n") if not line or (line and not line.startswith(ignore_tag))] # remove empty lines at the bottom for i in range(1, len(lines)): if not lines[-i].strip(): del lines[-i] else: break return "\n".join(lines[3:])
def _ssl_PRF(secret, seed, req_len): """ Provides the implementation of SSLv3 PRF function: SSLv3-PRF(secret, seed) = MD5(secret || SHA-1("A" || secret || seed)) || MD5(secret || SHA-1("BB" || secret || seed)) || MD5(secret || SHA-1("CCC" || secret || seed)) || ... req_len should not be more than 26 x 16 = 416. """ if req_len > 416: warning("_ssl_PRF() is not expected to provide more than 416 bytes") return "" d = [b"A", b"B", b"C", b"D", b"E", b"F", b"G", b"H", b"I", b"J", b"K", b"L", # noqa: E501 b"M", b"N", b"O", b"P", b"Q", b"R", b"S", b"T", b"U", b"V", b"W", b"X", # noqa: E501 b"Y", b"Z"] res = b"" hash_sha1 = _tls_hash_algs["SHA"]() hash_md5 = _tls_hash_algs["MD5"]() rounds = (req_len + hash_md5.hash_len - 1) // hash_md5.hash_len for i in range(rounds): label = d[i] * (i + 1) tmp = hash_sha1.digest(label + secret + seed) res += hash_md5.digest(secret + tmp) return res[:req_len]
def rec(n, l): sep = ':' if n and n % 2 == 0 else '' if n == 16: return l return rec(n + 1, [y + sep + '%.2x' % i # faster than '%s%s%.2x' % (y, sep, i) for i in range(*self.parsed[n]) for y in l])
def der2pem(der_string, obj="UNKNOWN"): """Convert DER octet string to PEM format (with optional header)""" # Encode a byte string in PEM format. Header advertizes <obj> type. pem_string = ("-----BEGIN %s-----\n" % obj).encode() base64_string = base64.b64encode(der_string) chunks = [base64_string[i:i + 64] for i in range(0, len(base64_string), 64)] # noqa: E501 pem_string += b'\n'.join(chunks) pem_string += ("\n-----END %s-----\n" % obj).encode() return pem_string
def corrupt_bits(s, p=0.01, n=None): """Flip a given percentage or number of bits from a string""" s = array.array("B",str(s)) l = len(s)*8 if n is None: n = max(1,int(l*p)) for i in random.sample(range(l), n): s[i/8] ^= 1 << (i%8) return s.tostring()
def m2i(self, pkt, x): nbr = struct.unpack("!H", x[2:4])[0] - 2 nbr //= 4 x = x[6:] list = [] for i in range(0, nbr): add = x[4 * i:4 * i + 4] list.append(inet_ntoa(add)) return list
def _fix(self): op = [] for k in range(self.size): o = random.choice(self._opts) if isinstance(o, str): op.append((o,self.rndstr*1)) else: op.append((o.name, o.randval()._fix())) return op
def do_copy(self, x): if hasattr(x, "copy"): return x.copy() if isinstance(x, list): x = x[:] for i in range(len(x)): if isinstance(x[i], BasePacket): x[i] = x[i].copy() return x
def corrupt_bytes(s, p=0.01, n=None): """Corrupt a given percentage or number of bytes from a string""" s = array.array("B",str(s)) l = len(s) if n is None: n = max(1,int(l*p)) for i in random.sample(range(l), n): s[i] = (s[i]+random.randint(1,255))%256 return s.tostring()
def __init__(self, size=None): super(RandBin, self).__init__(size=size, chars=b"".join(chb(c) for c in range(256))) # noqa: E501
0x0020: "PTCP-RTSyncPDU-followup", 0x0080: "PTCP-RTSyncPDU", 0xFC01: "Alarm High", 0xFE01: "Alarm Low", 0xFEFC: "DCP-Hello-Req", 0xFEFD: "DCP-Get-Set", 0xFEFE: "DCP-Identify-ReqPDU", 0xFEFF: "DCP-Identify-ResPDU", 0xFF00: "PTCP-AnnouncePDU", 0xFF20: "PTCP-FollowUpPDU", 0xFF40: "PTCP-DelayReqPDU", 0xFF41: "PTCP-DelayResPDU-followup", 0xFF42: "PTCP-DelayFuResPDU", 0xFF43: "PTCP-DelayResPDU", } for i in range(0x0100, 0x1000): PNIO_FRAME_IDS[i] = "RT_CLASS_3" for i in range(0x8000, 0xC000): PNIO_FRAME_IDS[i] = "RT_CLASS_1" for i in range(0xC000, 0xFC00): PNIO_FRAME_IDS[i] = "RT_CLASS_UDP" for i in range(0xFF80, 0xFF90): PNIO_FRAME_IDS[i] = "FragmentationFrameID" ################# # PROFINET IO # ################# class ProfinetIO(Packet): """Basic PROFINET IO dispatcher"""
class SkinnyMessageDialedNumber(Packet): name = 'dialed number' fields_desc = [ StrFixedLenField("number", "1337", 24), LEIntField("instance", 1), LEIntField("callid", 0) ] _skinny_message_callinfo_restrictions = [ 'CallerName', 'CallerNumber', 'CalledName', 'CalledNumber', 'OriginalCalledName', 'OriginalCalledNumber', 'LastRedirectName', 'LastRedirectNumber' ] + ['Bit%d' % i for i in range(8, 15)] class SkinnyMessageCallInfo(Packet): name = 'call information' fields_desc = [ StrFixedLenField("callername", "Jean Valjean", 40), StrFixedLenField("callernum", "1337", 24), StrFixedLenField("calledname", "Causette", 40), StrFixedLenField("callednum", "1034", 24), LEIntField("lineinstance", 1), LEIntField("callid", 0), StrFixedLenField("originalcalledname", "Causette", 40), StrFixedLenField("originalcallednum", "1034", 24), StrFixedLenField("lastredirectingname", "Causette", 40), StrFixedLenField("lastredirectingnum", "1034", 24),
def possible_shortens(dat): """Iterates through all possible compression parts in a DNS string""" yield dat for x in range(1, dat.count(b".")): yield dat.split(b".", x)[x]
def do_build(self): self._check() return super(LLDPDUManagementAddress, self).do_build() LLDPDU_CLASS_TYPES = { 0x00: LLDPDUEndOfLLDPDU, 0x01: LLDPDUChassisID, 0x02: LLDPDUPortID, 0x03: LLDPDUTimeToLive, 0x04: LLDPDUPortDescription, 0x05: LLDPDUSystemName, 0x06: LLDPDUSystemDescription, 0x07: LLDPDUSystemCapabilities, 0x08: LLDPDUManagementAddress, range(0x09, 0x7e): None, # reserved - future standardization 127: None # organisation specific TLV } class LLDPConfiguration(object): """ basic configuration for LLDP layer """ def __init__(self): self._strict_mode = True self.strict_mode_enable() def strict_mode_enable(self): """ enable strict mode and dissector debugging """
def _bind_someip_layers(): for i in range(15): bind_layers(UDP, SOMEIP, sport=30490 + i) bind_layers(TCP, SOMEIP, sport=30490 + i)
def __init__(self, size, term): RandString.__init__(self, size, "".join(map(chr, range(1, 256)))) self.term = term
def zerofree_randstring(l): """ Returns a random string of length l (l >= 0) without zero in it. """ return b"".join(struct.pack('B', random.randint(1, 255)) for _ in range(l))
class CDPMsgPortID(CDPMsgGeneric): name = "Port ID" fields_desc = [XShortEnumField("type", 0x0003, _cdp_tlv_types), FieldLenField("len", None, "iface", "!H", adjust=lambda pkt, x: x + 4), StrLenField("iface", "Port 1", length_from=lambda x:x.len - 4)] # noqa: E501 _cdp_capabilities = ["Router", "TransparentBridge", "SourceRouteBridge", "Switch", "Host", "IGMPCapable", "Repeater"] + ["Bit%d" % x for x in range(25, 0, -1)] class CDPMsgCapabilities(CDPMsgGeneric): name = "Capabilities" fields_desc = [XShortEnumField("type", 0x0004, _cdp_tlv_types), ShortField("len", 8), FlagsField("cap", 0, 32, _cdp_capabilities)] class CDPMsgSoftwareVersion(CDPMsgGeneric): name = "Software Version" type = 0x0005 class CDPMsgPlatform(CDPMsgGeneric):
def randstring(l): """ Returns a random string of length l (l >= 0) """ return b"".join(struct.pack('B', random.randint(0, 255)) for _ in range(l))
def hexdiff(x, y): """Show differences between 2 binary strings""" x = str(x)[::-1] y = str(y)[::-1] SUBST = 1 INSERT = 1 d = {(-1, -1): (0, (-1, -1))} for j in range(len(y)): d[-1, j] = d[-1, j - 1][0] + INSERT, (-1, j - 1) for i in range(len(x)): d[i, -1] = d[i - 1, -1][0] + INSERT, (i - 1, -1) for j in range(len(y)): for i in range(len(x)): d[i, j] = min( (d[i - 1, j - 1][0] + SUBST * (x[i] != y[j]), (i - 1, j - 1)), (d[i - 1, j][0] + INSERT, (i - 1, j)), (d[i, j - 1][0] + INSERT, (i, j - 1))) backtrackx = [] backtracky = [] i = len(x) - 1 j = len(y) - 1 while not (i == j == -1): i2, j2 = d[i, j][1] backtrackx.append(x[i2 + 1:i + 1]) backtracky.append(y[j2 + 1:j + 1]) i, j = i2, j2 x = y = i = 0 colorize = { 0: lambda x: x, -1: conf.color_theme.left, 1: conf.color_theme.right } dox = 1 doy = 0 l = len(backtrackx) while i < l: separate = 0 linex = backtrackx[i:i + 16] liney = backtracky[i:i + 16] xx = sum(len(k) for k in linex) yy = sum(len(k) for k in liney) if dox and not xx: dox = 0 doy = 1 if dox and linex == liney: doy = 1 if dox: xd = y j = 0 while not linex[j]: j += 1 xd -= 1 print(colorize[doy - dox]("%04x" % xd), end=' ') x += xx line = linex else: print(" ", end=' ') if doy: yd = y j = 0 while not liney[j]: j += 1 yd -= 1 print(colorize[doy - dox]("%04x" % yd), end=' ') y += yy line = liney else: print(" ", end=' ') print(" ", end=' ') cl = "" for j in range(16): if i + j < l: if line[j]: col = colorize[(linex[j] != liney[j]) * (doy - dox)] print(col("%02X" % orb(line[j])), end=' ') if linex[j] == liney[j]: cl += sane_color(line[j]) else: cl += col(sane(line[j])) else: print(" ", end=' ') cl += " " else: print(" ", end=' ') if j == 7: print("", end=' ') print(" ", cl) if doy or not yy: doy = 0 dox = 1 i += 16 else: if yy: dox = 0 doy = 1 else: i += 16
def _FlagsList(myfields): flags = ["Reserved%02d" % i for i in range(32)] for i, value in six.iteritems(myfields): flags[i] = value return flags
def _fix(self): stack = [None] index = [] current = stack i = 0 ln = len(self._regexp) interp = True while i < ln: c = self._regexp[i] i += 1 if c == '(': current = [current] current[0].append(current) elif c == '|': p = current[0] ch = p[-1] if not isinstance(ch, tuple): ch = ("choice", [current]) p[-1] = ch else: ch[1].append(current) current = [p] elif c == ')': ch = current[0][-1] if isinstance(ch, tuple): ch[1].append(current) index.append(current) current = current[0] elif c == '[' or c == '{': current = [current] current[0].append(current) interp = False elif c == ']': current = current[0] choice = RandRegExp.choice_expand("".join(current.pop()[1:])) current.append(RandChoice(*list(choice))) interp = True elif c == '}': current = current[0] num = "".join(current.pop()[1:]) e = current.pop() if "," not in num: n = int(num) current.append([current] + [e] * n) else: num_min, num_max = num.split(",") if not num_min: num_min = "0" if num_max: n = RandNum(int(num_min), int(num_max)) else: n = RandNumExpo(self._lambda, base=int(num_min)) current.append(("repeat", n)) current.append(e) interp = True elif c == '\\': c = self._regexp[i] if c == "s": c = RandChoice(" ", "\t") elif c in "0123456789": c = ("cite", ord(c) - 0x30) current.append(c) i += 1 elif not interp: current.append(c) elif c == '+': e = current.pop() current.append( [current] + [e] * (int(random.expovariate(self._lambda)) + 1)) # noqa: E501 elif c == '*': e = current.pop() current.append( [current] + [e] * int(random.expovariate(self._lambda))) # noqa: E501 elif c == '?': if random.randint(0, 1): current.pop() elif c == '.': current.append(RandChoice(*[chr(x) for x in range(256)])) elif c == '$' or c == '^': pass else: current.append(c) return RandRegExp.stack_fix(stack[1:], index)
class SkinnyMessageDialedNumber(Packet): name = 'dialed number' fields_desc = [ StrFixedLenField("number", "1337", 24), LEIntField("instance", 1), LEIntField("callid", 0) ] _skinny_message_callinfo_restrictions = [ 'CallerName', 'CallerNumber', 'CalledName', 'CalledNumber', 'OriginalCalledName', 'OriginalCalledNumber', 'LastRedirectName', 'LastRedirectNumber' ] + ['Bit%d' % i for i in range(8, 15)] # noqa: E501 class SkinnyMessageCallInfo(Packet): name = 'call information' fields_desc = [ StrFixedLenField("callername", "Jean Valjean", 40), StrFixedLenField("callernum", "1337", 24), StrFixedLenField("calledname", "Causette", 40), StrFixedLenField("callednum", "1034", 24), LEIntField("lineinstance", 1), LEIntField("callid", 0), StrFixedLenField("originalcalledname", "Causette", 40), StrFixedLenField("originalcallednum", "1034", 24), StrFixedLenField("lastredirectingname", "Causette", 40), StrFixedLenField("lastredirectingnum", "1034", 24),
return p class CDPMsgPortID(CDPMsgGeneric): name = "Port ID" fields_desc = [ XShortEnumField("type", 0x0003, _cdp_tlv_types), FieldLenField("len", None, "iface", "!H"), StrLenField("iface", "Port 1", length_from=lambda x: x.len - 4) ] _cdp_capabilities = [ "Router", "TransparentBridge", "SourceRouteBridge", "Switch", "Host", "IGMPCapable", "Repeater" ] + ["Bit%d" % x for x in range(25, 0, -1)] class CDPMsgCapabilities(CDPMsgGeneric): name = "Capabilities" fields_desc = [ XShortEnumField("type", 0x0004, _cdp_tlv_types), ShortField("len", 8), FlagsField("cap", 0, 32, _cdp_capabilities) ] class CDPMsgSoftwareVersion(CDPMsgGeneric): name = "Software Version" type = 0x0005
def __init__(self, size=None): RandString.__init__(self, size, "".join(map(chr, range(256))))
def matching_bits(byte1, byte2): for i in range(8): cur_mask = 0x80 >> i if (byte1 & cur_mask) != (byte2 & cur_mask): return i return 8
def _fix(self): s = "" for _ in range(self.size): s += random.choice(self.chars) return s
def main(): argv = sys.argv[1:] logger = logging.getLogger("scapy") logger.addHandler(logging.StreamHandler()) import scapy print(dash + " UTScapy - Scapy %s - %s" % (scapy.__version__, sys.version.split(" ")[0])) # Parse arguments FORMAT = Format.ANSI OUTPUTFILE = sys.stdout LOCAL = 0 NUM = None NON_ROOT = False KW_OK = [] KW_KO = [] DUMP = 0 DOCS = 0 CRC = True BREAKFAILED = True ONLYFAILED = False VERB = 3 GLOB_PREEXEC = "" PREEXEC_DICT = {} MODULES = [] TESTFILES = [] ANNOTATIONS_MODE = False INTERPRETER = False try: opts = getopt.getopt(argv, "o:t:T:c:f:hbln:m:k:K:DRdCiFqNP:s:x") for opt, optarg in opts[0]: if opt == "-h": usage() elif opt == "-b": BREAKFAILED = False elif opt == "-F": ONLYFAILED = True elif opt == "-q": VERB -= 1 elif opt == "-D": DUMP = 2 elif opt == "-R": DOCS = 1 elif opt == "-d": DUMP = 1 elif opt == "-C": CRC = False elif opt == "-i": INTERPRETER = True elif opt == "-x": ANNOTATIONS_MODE = True elif opt == "-P": GLOB_PREEXEC += "\n" + optarg elif opt == "-f": try: FORMAT = Format.from_string(optarg) except KeyError as msg: raise getopt.GetoptError("Unknown output format %s" % msg) elif opt == "-t": TESTFILES.append(optarg) TESTFILES = resolve_testfiles(TESTFILES) elif opt == "-T": TESTFILES.remove(optarg) elif opt == "-c": data = parse_config_file(optarg, VERB) BREAKFAILED = data.breakfailed ONLYFAILED = data.onlyfailed VERB = data.verb DUMP = data.dump CRC = data.crc PREEXEC_DICT = data.preexec GLOB_PREEXEC = data.global_preexec OUTPUTFILE = data.outfile TESTFILES = data.testfiles LOCAL = 1 if data.local else 0 NUM = data.num MODULES = data.modules KW_OK.extend(data.kw_ok) KW_KO.extend(data.kw_ko) try: FORMAT = Format.from_string(data.format) except KeyError as msg: raise getopt.GetoptError("Unknown output format %s" % msg) TESTFILES = resolve_testfiles(TESTFILES) for testfile in resolve_testfiles(data.remove_testfiles): try: TESTFILES.remove(testfile) except ValueError: error_m = "Cannot remove %s from test files" % testfile raise getopt.GetoptError(error_m) elif opt == "-o": OUTPUTFILE = optarg if not os.access(os.path.dirname(os.path.abspath(OUTPUTFILE)), os.W_OK): raise getopt.GetoptError("Cannot write to file %s" % OUTPUTFILE) elif opt == "-l": LOCAL = 1 elif opt == "-n": NUM = [] for v in (x.strip() for x in optarg.split(",")): try: NUM.append(int(v)) except ValueError: v1, v2 = [int(e) for e in v.split('-', 1)] NUM.extend(range(v1, v2 + 1)) elif opt == "-N": NON_ROOT = True elif opt == "-m": MODULES.append(optarg) elif opt == "-k": KW_OK.extend(optarg.split(",")) elif opt == "-K": KW_KO.extend(optarg.split(",")) except getopt.GetoptError as msg: print("ERROR:", msg) raise SystemExit if FORMAT in [Format.LIVE, Format.ANSI]: theme = DefaultTheme() else: theme = BlackAndWhite() # Disable tests if needed # Discard Python3 tests when using Python2 if six.PY2: KW_KO.append("python3_only") if VERB > 2: print(" " + arrow + " Python 2 mode") try: if NON_ROOT or os.getuid() != 0: # Non root # Discard root tests KW_KO.append("needs_root") if VERB > 2: print(" " + arrow + " Non-root mode") except AttributeError: pass if conf.use_pcap or WINDOWS: KW_KO.append("not_libpcap") if VERB > 2: print(" " + arrow + " libpcap mode") KW_KO.append("disabled") # Process extras if six.PY3: KW_KO.append("FIXME_py3") if ANNOTATIONS_MODE: try: from pyannotate_runtime import collect_types except ImportError: raise ImportError("Please install pyannotate !") collect_types.init_types_collection() collect_types.start() if VERB > 2: print(" " + arrow + " Booting scapy...") try: from scapy import all as scapy except Exception as e: print("[CRITICAL]: Cannot import Scapy: %s" % e) traceback.print_exc() sys.exit(1) # Abort the tests for m in MODULES: try: mod = import_module(m) six.moves.builtins.__dict__.update(mod.__dict__) except ImportError as e: raise getopt.GetoptError("cannot import [%s]: %s" % (m, e)) autorun_func = { Format.TEXT: scapy.autorun_get_text_interactive_session, Format.ANSI: scapy.autorun_get_ansi_interactive_session, Format.HTML: scapy.autorun_get_html_interactive_session, Format.LATEX: scapy.autorun_get_latex_interactive_session, Format.XUNIT: scapy.autorun_get_text_interactive_session, Format.LIVE: scapy.autorun_get_live_interactive_session, } if VERB > 2: print(" " + arrow + " Discovering tests files...") glob_output = "" glob_result = 0 glob_title = None UNIQUE = len(TESTFILES) == 1 # Resolve tags and asterix for prex in six.iterkeys(copy.copy(PREEXEC_DICT)): if "*" in prex: pycode = PREEXEC_DICT[prex] del PREEXEC_DICT[prex] for gl in glob.iglob(prex): _pycode = pycode.replace( "%name%", os.path.splitext(os.path.split(gl)[1])[0]) # noqa: E501 PREEXEC_DICT[gl] = _pycode pos_begin = 0 runned_campaigns = [] from scapy.main import _scapy_builtins scapy_ses = _scapy_builtins() import_UTscapy_tools(scapy_ses) # Execute all files for TESTFILE in TESTFILES: if VERB > 2: print(theme.green(dash + " Loading: %s" % TESTFILE)) PREEXEC = PREEXEC_DICT[ TESTFILE] if TESTFILE in PREEXEC_DICT else GLOB_PREEXEC with open(TESTFILE) as testfile: output, result, campaign = execute_campaign( testfile, OUTPUTFILE, PREEXEC, NUM, KW_OK, KW_KO, DUMP, DOCS, FORMAT, VERB, ONLYFAILED, CRC, INTERPRETER, autorun_func, theme, pos_begin=pos_begin, scapy_ses=copy.copy(scapy_ses)) runned_campaigns.append(campaign) pos_begin = campaign.end_pos if UNIQUE: glob_title = campaign.title glob_output += output if not result: glob_result = 1 if BREAKFAILED: break if VERB > 2: print(checkmark + " All campaigns executed. Writing output...") if ANNOTATIONS_MODE: collect_types.stop() collect_types.dump_stats("pyannotate_results") # Concenate outputs if FORMAT == Format.HTML: glob_output = pack_html_campaigns(runned_campaigns, glob_output, LOCAL, glob_title) if FORMAT == Format.LATEX: glob_output = pack_latex_campaigns(runned_campaigns, glob_output, LOCAL, glob_title) # Write the final output # Note: on Python 2, we force-encode to ignore ascii errors # on Python 3, we need to detect the type of stream if OUTPUTFILE == sys.stdout: print(glob_output, file=OUTPUTFILE) else: with open(OUTPUTFILE, "wb") as f: f.write( glob_output.encode("utf8", "ignore") if 'b' in f.mode or six.PY2 else glob_output) # Print end message if VERB > 2: if glob_result == 0: print(theme.green("UTscapy ended successfully")) else: print(theme.red("UTscapy ended with error code %s" % glob_result)) # Check active threads if VERB > 2: if threading.active_count() > 1: print("\nWARNING: UNFINISHED THREADS") print(threading.enumerate()) import multiprocessing processes = multiprocessing.active_children() if processes: print("\nWARNING: UNFINISHED PROCESSES") print(processes) sys.stdout.flush() # Return state return glob_result
def main(): argv = sys.argv[1:] ignore_globals = list(six.moves.builtins.__dict__) # Parse arguments FORMAT = Format.ANSI OUTPUTFILE = sys.stdout LOCAL = 0 NUM = None NON_ROOT = False KW_OK = [] KW_KO = [] DUMP = 0 DOCS = 0 CRC = True BREAKFAILED = True ONLYFAILED = False VERB = 3 GLOB_PREEXEC = "" PREEXEC_DICT = {} MODULES = [] TESTFILES = [] ANNOTATIONS_MODE = False INTERPRETER = False try: opts = getopt.getopt(argv, "o:t:T:c:f:hbln:m:k:K:DRdCiFqNP:s:x") for opt, optarg in opts[0]: if opt == "-h": usage() elif opt == "-b": BREAKFAILED = False elif opt == "-F": ONLYFAILED = True elif opt == "-q": VERB -= 1 elif opt == "-D": DUMP = 2 elif opt == "-R": DOCS = 1 elif opt == "-d": DUMP = 1 elif opt == "-C": CRC = False elif opt == "-i": INTERPRETER = True elif opt == "-x": ANNOTATIONS_MODE = True elif opt == "-P": GLOB_PREEXEC += "\n" + optarg elif opt == "-f": try: FORMAT = Format.from_string(optarg) except KeyError as msg: raise getopt.GetoptError("Unknown output format %s" % msg) elif opt == "-t": TESTFILES.append(optarg) TESTFILES = resolve_testfiles(TESTFILES) elif opt == "-T": TESTFILES.remove(optarg) elif opt == "-c": data = parse_config_file(optarg, VERB) BREAKFAILED = data.breakfailed ONLYFAILED = data.onlyfailed VERB = data.verb DUMP = data.dump CRC = data.crc PREEXEC_DICT = data.preexec GLOB_PREEXEC = data.global_preexec OUTPUTFILE = data.outfile TESTFILES = data.testfiles LOCAL = 1 if data.local else 0 NUM = data.num MODULES = data.modules KW_OK.extend(data.kw_ok) KW_KO.extend(data.kw_ko) try: FORMAT = Format.from_string(data.format) except KeyError as msg: raise getopt.GetoptError("Unknown output format %s" % msg) TESTFILES = resolve_testfiles(TESTFILES) for testfile in resolve_testfiles(data.remove_testfiles): try: TESTFILES.remove(testfile) except ValueError: error_m = "Cannot remove %s from test files" % testfile raise getopt.GetoptError(error_m) elif opt == "-o": OUTPUTFILE = optarg if not os.access(os.path.dirname(os.path.abspath(OUTPUTFILE)), os.W_OK): raise getopt.GetoptError("Cannot write to file %s" % OUTPUTFILE) elif opt == "-l": LOCAL = 1 elif opt == "-n": NUM = [] for v in (x.strip() for x in optarg.split(",")): try: NUM.append(int(v)) except ValueError: v1, v2 = [int(e) for e in v.split('-', 1)] NUM.extend(range(v1, v2 + 1)) elif opt == "-N": NON_ROOT = True elif opt == "-m": MODULES.append(optarg) elif opt == "-k": KW_OK.extend(optarg.split(",")) elif opt == "-K": KW_KO.extend(optarg.split(",")) # Disable tests if needed # Discard Python3 tests when using Python2 if six.PY2: KW_KO.append("python3_only") if VERB > 2: print("### Python 2 mode ###") try: if NON_ROOT or os.getuid() != 0: # Non root # Discard root tests KW_KO.append("netaccess") KW_KO.append("needs_root") if VERB > 2: print("### Non-root mode ###") except AttributeError: pass if conf.use_pcap: KW_KO.append("not_pcapdnet") if VERB > 2: print("### libpcap mode ###") # Process extras if six.PY3: KW_KO.append("FIXME_py3") if ANNOTATIONS_MODE: try: from pyannotate_runtime import collect_types except ImportError: raise ImportError("Please install pyannotate !") collect_types.init_types_collection() collect_types.start() if VERB > 2: print("### Booting scapy...", file=sys.stderr) try: from scapy import all as scapy except Exception as e: print("[CRITICAL]: Cannot import Scapy: %s" % e, file=sys.stderr) traceback.print_exc() sys.exit(1) # Abort the tests for m in MODULES: try: mod = import_module(m) six.moves.builtins.__dict__.update(mod.__dict__) except ImportError as e: raise getopt.GetoptError("cannot import [%s]: %s" % (m, e)) # Add SCAPY_ROOT_DIR environment variable, used for tests os.environ['SCAPY_ROOT_DIR'] = os.environ.get("PWD", os.getcwd()) except getopt.GetoptError as msg: print("ERROR:", msg, file=sys.stderr) raise SystemExit autorun_func = { Format.TEXT: scapy.autorun_get_text_interactive_session, Format.ANSI: scapy.autorun_get_ansi_interactive_session, Format.HTML: scapy.autorun_get_html_interactive_session, Format.LATEX: scapy.autorun_get_latex_interactive_session, Format.XUNIT: scapy.autorun_get_text_interactive_session, Format.LIVE: scapy.autorun_get_live_interactive_session, } if VERB > 2: print("### Starting tests...", file=sys.stderr) glob_output = "" glob_result = 0 glob_title = None UNIQUE = len(TESTFILES) == 1 # Resolve tags and asterix for prex in six.iterkeys(copy.copy(PREEXEC_DICT)): if "*" in prex: pycode = PREEXEC_DICT[prex] del PREEXEC_DICT[prex] for gl in glob.iglob(prex): _pycode = pycode.replace( "%name%", os.path.splitext(os.path.split(gl)[1])[0]) # noqa: E501 PREEXEC_DICT[gl] = _pycode pos_begin = 0 runned_campaigns = [] # Execute all files for TESTFILE in TESTFILES: if VERB > 2: print("### Loading:", TESTFILE, file=sys.stderr) PREEXEC = PREEXEC_DICT[ TESTFILE] if TESTFILE in PREEXEC_DICT else GLOB_PREEXEC with open(TESTFILE) as testfile: output, result, campaign = execute_campaign( testfile, OUTPUTFILE, PREEXEC, NUM, KW_OK, KW_KO, DUMP, DOCS, FORMAT, VERB, ONLYFAILED, CRC, INTERPRETER, autorun_func, pos_begin, ignore_globals) runned_campaigns.append(campaign) pos_begin = campaign.end_pos if UNIQUE: glob_title = campaign.title glob_output += output if not result: glob_result = 1 if BREAKFAILED: break if VERB > 2: print("### Writing output...", file=sys.stderr) if ANNOTATIONS_MODE: collect_types.stop() collect_types.dump_stats("pyannotate_results") # Concenate outputs if FORMAT == Format.HTML: glob_output = pack_html_campaigns(runned_campaigns, glob_output, LOCAL, glob_title) # Write the final output # Note: on Python 2, we force-encode to ignore ascii errors # on Python 3, we need to detect the type of stream if OUTPUTFILE == sys.stdout: OUTPUTFILE.write( glob_output.encode("utf8", "ignore") if 'b' in OUTPUTFILE.mode or six.PY2 else glob_output) else: with open(OUTPUTFILE, "wb") as f: f.write( glob_output.encode("utf8", "ignore") if 'b' in f.mode or six.PY2 else glob_output) # Delete scapy's test environment vars del os.environ['SCAPY_ROOT_DIR'] # Return state return glob_result
def main(argv): ignore_globals = list(six.moves.builtins.__dict__.keys()) # Parse arguments FORMAT = Format.ANSI TESTFILE = sys.stdin OUTPUTFILE = sys.stdout LOCAL = 0 NUM = None KW_OK = [] KW_KO = [] DUMP = 0 CRC = True ONLYFAILED = False VERB = 3 GLOB_PREEXEC = "" PREEXEC_DICT = {} SCAPY = "scapy" MODULES = [] TESTFILES = [] try: opts = getopt.getopt(argv, "o:t:T:c:f:hln:m:k:K:DdCFqP:s:") for opt, optarg in opts[0]: if opt == "-h": usage() elif opt == "-F": ONLYFAILED = True elif opt == "-q": VERB -= 1 elif opt == "-D": DUMP = 2 elif opt == "-d": DUMP = 1 elif opt == "-C": CRC = False elif opt == "-s": SCAPY = optarg elif opt == "-P": GLOB_PREEXEC += "\n" + optarg elif opt == "-f": try: FORMAT = Format.from_string(optarg) except KeyError as msg: raise getopt.GetoptError("Unknown output format %s" % msg) elif opt == "-t": TESTFILES.append(optarg) TESTFILES = resolve_testfiles(TESTFILES) elif opt == "-T": TESTFILES.remove(optarg) elif opt == "-c": data = parse_config_file(optarg, VERB) ONLYFAILED = data.onlyfailed VERB = data.verb DUMP = data.dump CRC = data.crc SCAPY = data.scapy PREEXEC_DICT = data.preexec GLOB_PREEXEC = data.global_preexec OUTPUTFILE = data.outfile TESTFILES = data.testfiles LOCAL = 1 if data.local else 0 NUM = data.num MODULES = data.modules KW_OK = [data.kw_ok] KW_KO = [data.kw_ko] try: FORMAT = Format.from_string(data.format) except KeyError as msg: raise getopt.GetoptError("Unknown output format %s" % msg) TESTFILES = resolve_testfiles(TESTFILES) for testfile in resolve_testfiles(data.remove_testfiles): TESTFILES.remove(testfile) elif opt == "-o": OUTPUTFILE = open(optarg, "wb") elif opt == "-l": LOCAL = 1 elif opt == "-n": NUM = [] for v in (x.strip() for x in optarg.split(",")): try: NUM.append(int(v)) except ValueError: v1, v2 = [int(e) for e in v.split('-', 1)] NUM.extend(range(v1, v2 + 1)) elif opt == "-m": MODULES.append(optarg) elif opt == "-k": KW_OK.append(optarg.split(",")) elif opt == "-K": KW_KO.append(optarg.split(",")) # Discard Python3 tests when using Python2 if six.PY2: KW_KO.append(["python3_only"]) if VERB > 2: print("### Booting scapy...", file=sys.stderr) try: from scapy import all as scapy except ImportError as e: raise getopt.GetoptError("cannot import [%s]: %s" % (SCAPY, e)) for m in MODULES: try: mod = import_module(m) six.moves.builtins.__dict__.update(mod.__dict__) except ImportError as e: raise getopt.GetoptError("cannot import [%s]: %s" % (m, e)) if WINDOWS: from scapy.arch.windows import route_add_loopback route_add_loopback() except getopt.GetoptError as msg: print("ERROR:", msg, file=sys.stderr) raise SystemExit autorun_func = { Format.TEXT: scapy.autorun_get_text_interactive_session, Format.ANSI: scapy.autorun_get_ansi_interactive_session, Format.HTML: scapy.autorun_get_html_interactive_session, Format.LATEX: scapy.autorun_get_latex_interactive_session, Format.XUNIT: scapy.autorun_get_text_interactive_session, } if VERB > 2: print("### Starting tests...", file=sys.stderr) glob_output = "" glob_result = 0 glob_title = None UNIQUE = len(TESTFILES) == 1 # Resolve tags and asterix for prex in six.iterkeys(copy.copy(PREEXEC_DICT)): if "*" in prex: pycode = PREEXEC_DICT[prex] del PREEXEC_DICT[prex] for gl in glob.iglob(prex): _pycode = pycode.replace( "%name%", os.path.splitext(os.path.split(gl)[1])[0]) # noqa: E501 PREEXEC_DICT[gl] = _pycode pos_begin = 0 runned_campaigns = [] # Execute all files for TESTFILE in TESTFILES: if VERB > 2: print("### Loading:", TESTFILE, file=sys.stderr) PREEXEC = PREEXEC_DICT[ TESTFILE] if TESTFILE in PREEXEC_DICT else GLOB_PREEXEC # noqa: E501 output, result, campaign = execute_campaign( open(TESTFILE), OUTPUTFILE, PREEXEC, NUM, KW_OK, KW_KO, DUMP, FORMAT, VERB, ONLYFAILED, # noqa: E501 CRC, autorun_func, pos_begin, ignore_globals) # noqa: E501 runned_campaigns.append(campaign) pos_begin = campaign.end_pos if UNIQUE: glob_title = campaign.title glob_output += output if not result: glob_result = 1 break if VERB > 2: print("### Writing output...", file=sys.stderr) # Concenate outputs if FORMAT == Format.HTML: glob_output = pack_html_campaigns(runned_campaigns, glob_output, LOCAL, glob_title) # noqa: E501 OUTPUTFILE.write( glob_output.encode("utf8", "ignore") if 'b' in OUTPUTFILE.mode else glob_output) OUTPUTFILE.close() # Return state return glob_result
class SkinnyMessageKeypadButton(Packet): name = 'keypad button' fields_desc = [LEIntField("key", 0), LEIntField("instance", 1), LEIntField("callid", 0)] class SkinnyMessageDialedNumber(Packet): name = 'dialed number' fields_desc = [StrFixedLenField("number", "1337", 24), LEIntField("instance", 1), LEIntField("callid", 0)] _skinny_message_callinfo_restrictions = ['CallerName', 'CallerNumber', 'CalledName', 'CalledNumber', 'OriginalCalledName', 'OriginalCalledNumber', 'LastRedirectName', 'LastRedirectNumber'] + ['Bit%d' % i for i in range(8, 15)] class SkinnyMessageCallInfo(Packet): name = 'call information' fields_desc = [StrFixedLenField("callername", "Jean Valjean", 40), StrFixedLenField("callernum", "1337", 24), StrFixedLenField("calledname", "Causette", 40), StrFixedLenField("callednum", "1034", 24), LEIntField("lineinstance", 1), LEIntField("callid", 0), StrFixedLenField("originalcalledname", "Causette", 40), StrFixedLenField("originalcallednum", "1034", 24), StrFixedLenField("lastredirectingname", "Causette", 40), StrFixedLenField("lastredirectingnum", "1034", 24), LEIntField("originalredirectreason", 0),
# Copyright (C) Guillaume Valadon # This program is published under a GPLv2 license import time from scapy.all import * from scapy.modules.six.moves import range if WINDOWS: route_add_loopback() N = 10000 raw_packet = b'E\x00\x00(\x00\x01\x00\x00@\x11|\xc2\x7f\x00\x00\x01\x7f\x00\x00\x01\x005\x005\x00\x14\x00Z\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00' start = time.time() for i in range(N): p = IP() / UDP() / DNS() assert raw(p) == raw_packet print("Build - %.2fs" % (time.time() - start)) start = time.time() for i in range(N): p = IP(raw_packet) assert DNS in p print("Dissect - %.2fs" % (time.time() - start)) start = time.time() for i in range(N): p = IP() / UDP() / DNS() s = raw(p) assert s == raw_packet
def __iter__(self): for d in range(*self.parsed[3]): for c in range(*self.parsed[2]): for b in range(*self.parsed[1]): for a in range(*self.parsed[0]): yield "%i.%i.%i.%i" % (a, b, c, d)
LEIntField("callid", 0)] class SkinnyMessageDialedNumber(Packet): name='dialed number' fields_desc = [ StrFixedLenField("number", "1337", 24), LEIntField("instance", 1), LEIntField("callid", 0)] _skinny_message_callinfo_restrictions = ['CallerName' , 'CallerNumber' , 'CalledName' , 'CalledNumber' , 'OriginalCalledName' , 'OriginalCalledNumber' , 'LastRedirectName' , 'LastRedirectNumber'] + ['Bit%d' % i for i in range(8,15)] class SkinnyMessageCallInfo(Packet): name='call information' fields_desc = [ StrFixedLenField("callername", "Jean Valjean", 40), StrFixedLenField("callernum", "1337", 24), StrFixedLenField("calledname", "Causette", 40), StrFixedLenField("callednum", "1034", 24), LEIntField("lineinstance", 1), LEIntField("callid", 0), StrFixedLenField("originalcalledname", "Causette", 40), StrFixedLenField("originalcallednum", "1034", 24), StrFixedLenField("lastredirectingname", "Causette", 40), StrFixedLenField("lastredirectingnum", "1034", 24), LEIntField("originalredirectreason", 0), LEIntField("lastredirectreason", 0), StrFixedLenField('voicemailboxG', b'\0'*24, 24),
def _fix(self): s = b"" for _ in range(self.size): rdm_chr = random.choice(self.chars) s += rdm_chr if isinstance(rdm_chr, str) else chb(rdm_chr) return s
class LLDPDU(Packet): """ base class for all LLDP data units """ TYPES = { 0x00: 'end of LLDPDU', 0x01: 'chassis id', 0x02: 'port id', 0x03: 'time to live', 0x04: 'port description', 0x05: 'system name', 0x06: 'system description', 0x07: 'system capabilities', 0x08: 'management address', range(0x09, 0x7e): 'reserved - future standardization', 127: 'organisation specific TLV' } DOT1Q_HEADER_LEN = 4 ETHER_HEADER_LEN = 14 ETHER_FSC_LEN = 4 ETHER_FRAME_MIN_LEN = 64 LAYER_STACK = [] LAYER_MULTIPLICITIES = {} def guess_payload_class(self, payload): # type is a 7-bit bitfield spanning bits 1..7 -> div 2 try: lldpdu_tlv_type = orb(payload[0]) // 2 return LLDPDU_CLASS_TYPES.get(lldpdu_tlv_type, conf.raw_layer) except IndexError: return conf.raw_layer @staticmethod def _dot1q_headers_size(layer): """ calculate size of lower dot1q layers (if present) :param layer: the layer to start at :return: size of vlan headers, layer below lowest vlan header """ vlan_headers_size = 0 under_layer = layer while under_layer and isinstance(under_layer, Dot1Q): vlan_headers_size += LLDPDU.DOT1Q_HEADER_LEN under_layer = under_layer.underlayer return vlan_headers_size, under_layer def post_build(self, pkt, pay): last_layer = not pay if last_layer and conf.contribs['LLDP'].strict_mode() and \ type(self).__name__ != LLDPDUEndOfLLDPDU.__name__: raise LLDPInvalidLastLayerException('Last layer must be instance ' 'of LLDPDUEndOfLLDPDU - ' 'got {}'.format( type(self).__name__)) under_layer = self.underlayer if under_layer is None: if conf.contribs['LLDP'].strict_mode(): raise LLDPMissingLowerLayer('No lower layer (Ethernet ' 'or Dot1Q) provided.') else: return pkt + pay if isinstance(under_layer, LLDPDU): return pkt + pay frame_size, under_layer = LLDPDU._dot1q_headers_size(under_layer) if not under_layer or not isinstance(under_layer, Ether): if conf.contribs['LLDP'].strict_mode(): raise LLDPMissingLowerLayer('No Ethernet layer provided.') else: return pkt + pay frame_size += LLDPDU.ETHER_HEADER_LEN frame_size += len(pkt) + len(pay) + LLDPDU.ETHER_FSC_LEN if frame_size < LLDPDU.ETHER_FRAME_MIN_LEN: return pkt + pay + b'\x00' * ( LLDPDU.ETHER_FRAME_MIN_LEN - frame_size) # noqa: E501 return pkt + pay @staticmethod def _frame_structure_check(structure_description): """ check if the structure of the frame is conform to the basic frame structure defined by the standard :param structure_description: string-list reflecting LLDP-msg structure """ standard_frame_structure = [ LLDPDUChassisID.__name__, LLDPDUPortID.__name__, LLDPDUTimeToLive.__name__, '<...>', LLDPDUEndOfLLDPDU.__name__ ] if len(structure_description) < 4: raise LLDPInvalidFrameStructure( 'Invalid frame structure.\ngot: {}\nexpected: ' '{}'.format(' '.join(structure_description), ' '.join(standard_frame_structure))) for idx, layer_name in enumerate(standard_frame_structure): if layer_name == '<...>': break if layer_name != structure_description[idx]: raise LLDPInvalidFrameStructure( 'Invalid frame structure.\ngot: {}\nexpected: ' '{}'.format(' '.join(structure_description), ' '.join(standard_frame_structure))) if structure_description[-1] != standard_frame_structure[-1]: raise LLDPInvalidFrameStructure( 'Invalid frame structure.\ngot: {}\nexpected: ' '{}'.format(' '.join(structure_description), ' '.join(standard_frame_structure))) @staticmethod def _tlv_multiplicities_check(tlv_type_count): """ check if multiplicity of present TLVs conforms to the standard :param tlv_type_count: dict containing counte-per-TLV """ # * : 0..n, 1 : one and only one. standard_multiplicities = { LLDPDUEndOfLLDPDU.__name__: 1, LLDPDUChassisID.__name__: 1, LLDPDUPortID.__name__: 1, LLDPDUTimeToLive.__name__: 1, LLDPDUPortDescription: '*', LLDPDUSystemName: '*', LLDPDUSystemDescription: '*', LLDPDUSystemCapabilities: '*', LLDPDUManagementAddress: '*' } for tlv_type_name in standard_multiplicities: standard_tlv_multiplicity = \ standard_multiplicities[tlv_type_name] if standard_tlv_multiplicity == '*': continue try: if tlv_type_count[tlv_type_name] != standard_tlv_multiplicity: raise LLDPInvalidTLVCount( 'Invalid number of entries for TLV type ' '{} - expected {} entries, got ' '{}'.format(tlv_type_name, standard_tlv_multiplicity, tlv_type_count[tlv_type_name])) except KeyError: raise LLDPInvalidTLVCount('Missing TLV layer of type ' '{}.'.format(tlv_type_name)) def pre_dissect(self, s): if conf.contribs['LLDP'].strict_mode(): if self.__class__.__name__ == 'LLDPDU': LLDPDU.LAYER_STACK = [] LLDPDU.LAYER_MULTIPLICITIES = {} else: LLDPDU.LAYER_STACK.append(self.__class__.__name__) try: LLDPDU.LAYER_MULTIPLICITIES[self.__class__.__name__] += 1 except KeyError: LLDPDU.LAYER_MULTIPLICITIES[self.__class__.__name__] = 1 return s def dissection_done(self, pkt): if self.__class__.__name__ == 'LLDPDU' and \ conf.contribs['LLDP'].strict_mode(): LLDPDU._frame_structure_check(LLDPDU.LAYER_STACK) LLDPDU._tlv_multiplicities_check(LLDPDU.LAYER_MULTIPLICITIES) super(LLDPDU, self).dissection_done(pkt) def _check(self): """Overwrited by LLDPU objects""" pass def post_dissect(self, s): self._check() return super(LLDPDU, self).post_dissect(s) def do_build(self): self._check() return super(LLDPDU, self).do_build()
def _fix(self): s = b"" for _ in range(self.size): s += chb(random.choice(self.chars)) return s
def gen_TKIP_RC4_key(TSC, TA, TK): """Implement TKIP WEPSeed generation TSC: packet IV TA: target addr bytes TK: temporal key """ assert len(TSC) == 6 assert len(TA) == 6 assert len(TK) == 16 assert all(isinstance(x, six.integer_types) for x in TSC + TA + TK) # Phase 1 # 802.11i p.54 # Phase 1 - Step 1 TTAK = [] TTAK.append(_MK16(TSC[3], TSC[2])) TTAK.append(_MK16(TSC[5], TSC[4])) TTAK.append(_MK16(TA[1], TA[0])) TTAK.append(_MK16(TA[3], TA[2])) TTAK.append(_MK16(TA[5], TA[4])) # Phase 1 - Step 2 for i in range(PHASE1_LOOP_CNT): j = 2 * (i & 1) TTAK[0] = _CAST16( TTAK[0] + _SBOX16(TTAK[4] ^ _MK16(TK[1 + j], TK[0 + j]))) # noqa: E501 TTAK[1] = _CAST16( TTAK[1] + _SBOX16(TTAK[0] ^ _MK16(TK[5 + j], TK[4 + j]))) # noqa: E501 TTAK[2] = _CAST16( TTAK[2] + _SBOX16(TTAK[1] ^ _MK16(TK[9 + j], TK[8 + j]))) # noqa: E501 TTAK[3] = _CAST16( TTAK[3] + _SBOX16(TTAK[2] ^ _MK16(TK[13 + j], TK[12 + j]))) # noqa: E501 TTAK[4] = _CAST16(TTAK[4] + _SBOX16(TTAK[3] ^ _MK16(TK[1 + j], TK[0 + j])) + i) # noqa: E501 # Phase 2 # 802.11i p.56 # Phase 2 - Step 1 PPK = list(TTAK) PPK.append(_CAST16(TTAK[4] + _MK16(TSC[1], TSC[0]))) # Phase 2 - Step 2 PPK[0] = _CAST16(PPK[0] + _SBOX16(PPK[5] ^ _MK16(TK[1], TK[0]))) PPK[1] = _CAST16(PPK[1] + _SBOX16(PPK[0] ^ _MK16(TK[3], TK[2]))) PPK[2] = _CAST16(PPK[2] + _SBOX16(PPK[1] ^ _MK16(TK[5], TK[4]))) PPK[3] = _CAST16(PPK[3] + _SBOX16(PPK[2] ^ _MK16(TK[7], TK[6]))) PPK[4] = _CAST16(PPK[4] + _SBOX16(PPK[3] ^ _MK16(TK[9], TK[8]))) PPK[5] = _CAST16(PPK[5] + _SBOX16(PPK[4] ^ _MK16(TK[11], TK[10]))) PPK[0] = _CAST16(PPK[0] + _RotR1(PPK[5] ^ _MK16(TK[13], TK[12]))) PPK[1] = _CAST16(PPK[1] + _RotR1(PPK[0] ^ _MK16(TK[15], TK[14]))) PPK[2] = _CAST16(PPK[2] + _RotR1(PPK[1])) PPK[3] = _CAST16(PPK[3] + _RotR1(PPK[2])) PPK[4] = _CAST16(PPK[4] + _RotR1(PPK[3])) PPK[5] = _CAST16(PPK[5] + _RotR1(PPK[4])) # Phase 2 - Step 3 WEPSeed = [] WEPSeed.append(TSC[1]) WEPSeed.append((TSC[1] | 0x20) & 0x7f) WEPSeed.append(TSC[0]) WEPSeed.append(((PPK[5] ^ _MK16(TK[1], TK[0])) >> 1) & 0xFF) for i in range(6): WEPSeed.append(PPK[i] & 0xFF) WEPSeed.append(PPK[i] >> 8) assert len(WEPSeed) == 16 return "".join([chr(x) for x in WEPSeed])
def __iter__(self): # type: () -> Iterator[str] # Python 2 won't handle huge (> sys.maxint) values in range() for i in range(self.count): yield self.int2ip(self.start + i)