def _fix(self): if self.bytecount == 0: return "" val = () for _ in range(self.bytecount): val += (RandByte(),) return self.format % val
def p0f_impersonate(pkt, osgenre=None, osdetails=None, signature=None, extrahops=0, mtu=1500, uptime=None): """Modifies pkt so that p0f will think it has been sent by a specific OS. If osdetails is None, then we randomly pick up a personality matching osgenre. If osgenre and signature are also None, we use a local signature (using p0f_getlocalsigs). If signature is specified (as a tuple), we use the signature. For now, only TCP Syn packets are supported. Some specifications of the p0f.fp file are not (yet) implemented.""" pkt = pkt.copy() #pkt = pkt.__class__(raw(pkt)) while pkt.haslayer(IP) and pkt.haslayer(TCP): pkt = pkt.getlayer(IP) if isinstance(pkt.payload, TCP): break pkt = pkt.payload if not isinstance(pkt, IP) or not isinstance(pkt.payload, TCP): raise TypeError("Not a TCP/IP packet") db = p0f_selectdb(pkt.payload.flags) if osgenre: pb = db.get_base() if pb is None: pb = [] pb = [x for x in pb if x[6] == osgenre] if osdetails: pb = [x for x in pb if x[7] == osdetails] elif signature: pb = [signature] else: pb = p0f_getlocalsigs()[db] if db == p0fr_kdb: # 'K' quirk <=> RST+ACK if pkt.payload.flags & 0x4 == 0x4: pb = [x for x in pb if 'K' in x[5]] else: pb = [x for x in pb if 'K' not in x[5]] if not pb: raise Scapy_Exception("No match in the p0f database") pers = pb[random.randint(0, len(pb) - 1)] # options (we start with options because of MSS) # Take the options already set as "hints" to use in the new packet if we # can. MSS, WScale and Timestamp can all be wildcarded in a signature, so # we'll use the already-set values if they're valid integers. orig_opts = dict(pkt.payload.options) int_only = lambda val: val if isinstance(val, six.integer_types) else None mss_hint = int_only(orig_opts.get('MSS')) wscale_hint = int_only(orig_opts.get('WScale')) ts_hint = [int_only(o) for o in orig_opts.get('Timestamp', (None, None))] options = [] if pers[4] != '.': for opt in pers[4].split(','): if opt[0] == 'M': # MSS might have a maximum size because of window size # specification if pers[0][0] == 'S': maxmss = (2**16-1) // int(pers[0][1:]) else: maxmss = (2**16-1) # disregard hint if out of range if mss_hint and not 0 <= mss_hint <= maxmss: mss_hint = None # If we have to randomly pick up a value, we cannot use # scapy RandXXX() functions, because the value has to be # set in case we need it for the window size value. That's # why we use random.randint() if opt[1:] == '*': if mss_hint is not None: options.append(('MSS', mss_hint)) else: options.append(('MSS', random.randint(1, maxmss))) elif opt[1] == '%': coef = int(opt[2:]) if mss_hint is not None and mss_hint % coef == 0: options.append(('MSS', mss_hint)) else: options.append(( 'MSS', coef*random.randint(1, maxmss//coef))) else: options.append(('MSS', int(opt[1:]))) elif opt[0] == 'W': if wscale_hint and not 0 <= wscale_hint < 2**8: wscale_hint = None if opt[1:] == '*': if wscale_hint is not None: options.append(('WScale', wscale_hint)) else: options.append(('WScale', RandByte())) elif opt[1] == '%': coef = int(opt[2:]) if wscale_hint is not None and wscale_hint % coef == 0: options.append(('WScale', wscale_hint)) else: options.append(( 'WScale', coef*RandNum(min=1, max=(2**8-1)//coef))) else: options.append(('WScale', int(opt[1:]))) elif opt == 'T0': options.append(('Timestamp', (0, 0))) elif opt == 'T': # Determine first timestamp. if uptime is not None: ts_a = uptime elif ts_hint[0] and 0 < ts_hint[0] < 2**32: # Note: if first ts is 0, p0f registers it as "T0" not "T", # hence we don't want to use the hint if it was 0. ts_a = ts_hint[0] else: ts_a = random.randint(120, 100*60*60*24*365) # Determine second timestamp. if 'T' not in pers[5]: ts_b = 0 elif ts_hint[1] and 0 < ts_hint[1] < 2**32: ts_b = ts_hint[1] else: # FIXME: RandInt() here does not work (bug (?) in # TCPOptionsField.m2i often raises "OverflowError: # long int too large to convert to int" in: # oval = struct.pack(ofmt, *oval)" # Actually, this is enough to often raise the error: # struct.pack('I', RandInt()) ts_b = random.randint(1, 2**32-1) options.append(('Timestamp', (ts_a, ts_b))) elif opt == 'S': options.append(('SAckOK', '')) elif opt == 'N': options.append(('NOP', None)) elif opt == 'E': options.append(('EOL', None)) elif opt[0] == '?': if int(opt[1:]) in TCPOptions[0]: optname = TCPOptions[0][int(opt[1:])][0] optstruct = TCPOptions[0][int(opt[1:])][1] options.append((optname, struct.unpack(optstruct, RandString(struct.calcsize(optstruct))._fix()))) else: options.append((int(opt[1:]), '')) ## FIXME: qqP not handled else: warning("unhandled TCP option " + opt) pkt.payload.options = options # window size if pers[0] == '*': pkt.payload.window = RandShort() elif pers[0].isdigit(): pkt.payload.window = int(pers[0]) elif pers[0][0] == '%': coef = int(pers[0][1:]) pkt.payload.window = coef * RandNum(min=1, max=(2**16-1)//coef) elif pers[0][0] == 'T': pkt.payload.window = mtu * int(pers[0][1:]) elif pers[0][0] == 'S': ## needs MSS set mss = [x for x in options if x[0] == 'MSS'] if not mss: raise Scapy_Exception("TCP window value requires MSS, and MSS option not set") pkt.payload.window = mss[0][1] * int(pers[0][1:]) else: raise Scapy_Exception('Unhandled window size specification') # ttl pkt.ttl = pers[1]-extrahops # DF flag pkt.flags |= (2 * pers[2]) ## FIXME: ss (packet size) not handled (how ? may be with D quirk ## if present) # Quirks if pers[5] != '.': for qq in pers[5]: ## FIXME: not handled: P, I, X, ! # T handled with the Timestamp option if qq == 'Z': pkt.id = 0 elif qq == 'U': pkt.payload.urgptr = RandShort() elif qq == 'A': pkt.payload.ack = RandInt() elif qq == 'F': if db == p0fo_kdb: pkt.payload.flags |= 0x20 # U else: pkt.payload.flags |= random.choice([8, 32, 40]) # P/U/PU elif qq == 'D' and db != p0fo_kdb: pkt /= conf.raw_layer(load=RandString(random.randint(1, 10))) # XXX p0fo.fp elif qq == 'Q': pkt.payload.seq = pkt.payload.ack #elif qq == '0': pkt.payload.seq = 0 #if db == p0fr_kdb: # '0' quirk is actually not only for p0fr.fp (see # packet2p0f()) if '0' in pers[5]: pkt.payload.seq = 0 elif pkt.payload.seq == 0: pkt.payload.seq = RandInt() while pkt.underlayer: pkt = pkt.underlayer return pkt
def p0f_impersonate(pkt, osgenre=None, osdetails=None, signature=None, extrahops=0, mtu=1500, uptime=None): """Modifies pkt so that p0f will think it has been sent by a specific OS. If osdetails is None, then we randomly pick up a personality matching osgenre. If osgenre and signature are also None, we use a local signature (using p0f_getlocalsigs). If signature is specified (as a tuple), we use the signature. For now, only TCP Syn packets are supported. Some specifications of the p0f.fp file are not (yet) implemented.""" pkt = pkt.copy() #pkt = pkt.__class__(str(pkt)) while pkt.haslayer(IP) and pkt.haslayer(TCP): pkt = pkt.getlayer(IP) if isinstance(pkt.payload, TCP): break pkt = pkt.payload if not isinstance(pkt, IP) or not isinstance(pkt.payload, TCP): raise TypeError("Not a TCP/IP packet") if uptime is None: uptime = random.randint(120, 100 * 60 * 60 * 24 * 365) db = p0f_selectdb(pkt.payload.flags) if osgenre: pb = db.get_base() if pb is None: pb = [] pb = filter(lambda x: x[6] == osgenre, pb) if osdetails: pb = filter(lambda x: x[7] == osdetails, pb) elif signature: pb = [signature] else: pb = p0f_getlocalsigs()[db] if db == p0fr_kdb: # 'K' quirk <=> RST+ACK if pkt.payload.flags & 0x4 == 0x4: pb = filter(lambda x: 'K' in x[5], pb) else: pb = filter(lambda x: 'K' not in x[5], pb) if not pb: raise Scapy_Exception("No match in the p0f database") pers = pb[random.randint(0, len(pb) - 1)] # options (we start with options because of MSS) ## TODO: let the options already set if they are valid options = [] if pers[4] != '.': for opt in pers[4].split(','): if opt[0] == 'M': # MSS might have a maximum size because of window size # specification if pers[0][0] == 'S': maxmss = (2**16 - 1) / int(pers[0][1:]) else: maxmss = (2**16 - 1) # If we have to randomly pick up a value, we cannot use # scapy RandXXX() functions, because the value has to be # set in case we need it for the window size value. That's # why we use random.randint() if opt[1:] == '*': options.append(('MSS', random.randint(1, maxmss))) elif opt[1] == '%': coef = int(opt[2:]) options.append( ('MSS', coef * random.randint(1, maxmss / coef))) else: options.append(('MSS', int(opt[1:]))) elif opt[0] == 'W': if opt[1:] == '*': options.append(('WScale', RandByte())) elif opt[1] == '%': coef = int(opt[2:]) options.append( ('WScale', coef * RandNum(min=1, max=(2**8 - 1) / coef))) else: options.append(('WScale', int(opt[1:]))) elif opt == 'T0': options.append(('Timestamp', (0, 0))) elif opt == 'T': if 'T' in pers[5]: # FIXME: RandInt() here does not work (bug (?) in # TCPOptionsField.m2i often raises "OverflowError: # long int too large to convert to int" in: # oval = struct.pack(ofmt, *oval)" # Actually, this is enough to often raise the error: # struct.pack('I', RandInt()) options.append( ('Timestamp', (uptime, random.randint(1, 2**32 - 1)))) else: options.append(('Timestamp', (uptime, 0))) elif opt == 'S': options.append(('SAckOK', '')) elif opt == 'N': options.append(('NOP', None)) elif opt == 'E': options.append(('EOL', None)) elif opt[0] == '?': if int(opt[1:]) in TCPOptions[0]: optname = TCPOptions[0][int(opt[1:])][0] optstruct = TCPOptions[0][int(opt[1:])][1] options.append( (optname, struct.unpack( optstruct, RandString(struct.calcsize(optstruct))._fix()))) else: options.append((int(opt[1:]), '')) ## FIXME: qqP not handled else: warning("unhandled TCP option " + opt) pkt.payload.options = options # window size if pers[0] == '*': pkt.payload.window = RandShort() elif pers[0].isdigit(): pkt.payload.window = int(pers[0]) elif pers[0][0] == '%': coef = int(pers[0][1:]) pkt.payload.window = coef * RandNum(min=1, max=(2**16 - 1) / coef) elif pers[0][0] == 'T': pkt.payload.window = mtu * int(pers[0][1:]) elif pers[0][0] == 'S': ## needs MSS set MSS = filter(lambda x: x[0] == 'MSS', options) if not filter(lambda x: x[0] == 'MSS', options): raise Scapy_Exception( "TCP window value requires MSS, and MSS option not set") pkt.payload.window = filter(lambda x: x[0] == 'MSS', options)[0][1] * int(pers[0][1:]) else: raise Scapy_Exception('Unhandled window size specification') # ttl pkt.ttl = pers[1] - extrahops # DF flag pkt.flags |= (2 * pers[2]) ## FIXME: ss (packet size) not handled (how ? may be with D quirk ## if present) # Quirks if pers[5] != '.': for qq in pers[5]: ## FIXME: not handled: P, I, X, ! # T handled with the Timestamp option if qq == 'Z': pkt.id = 0 elif qq == 'U': pkt.payload.urgptr = RandShort() elif qq == 'A': pkt.payload.ack = RandInt() elif qq == 'F': if db == p0fo_kdb: pkt.payload.flags |= 0x20 # U else: pkt.payload.flags |= RandChoice(8, 32, 40) #P / U / PU elif qq == 'D' and db != p0fo_kdb: pkt /= conf.raw_layer(load=RandString(random.randint( 1, 10))) # XXX p0fo.fp elif qq == 'Q': pkt.payload.seq = pkt.payload.ack #elif qq == '0': pkt.payload.seq = 0 #if db == p0fr_kdb: # '0' quirk is actually not only for p0fr.fp (see # packet2p0f()) if '0' in pers[5]: pkt.payload.seq = 0 elif pkt.payload.seq == 0: pkt.payload.seq = RandInt() while pkt.underlayer: pkt = pkt.underlayer return pkt
def p0f_impersonate(pkt, osgenre=None, osdetails=None, signature=None, extrahops=0, mtu=1500, uptime=None): """Modifies pkt so that p0f will think it has been sent by a specific OS. Either osgenre or signature is required to impersonate. If signature is specified (as a raw string), we use the signature. signature format: "ip_ver:ttl:ip_opt_len:mss:window,wscale:opt_layout:quirks:pay_class" If osgenre is specified, we randomly pick a signature with a label that matches osgenre (and osdetails, if specified). Note: osgenre is case sensitive ("linux" -> "Linux" etc.), and osdetails is a substring of a label flavor ("7", "8" and "7 or 8" will all match the label "s:win:Windows:7 or 8") For now, only TCP SYN/SYN+ACK packets are supported.""" pkt = validate_packet(pkt) if not osgenre and not signature: raise ValueError("osgenre or signature is required to impersonate!") tcp = pkt[TCP] tcp_type = tcp.flags & (0x02 | 0x10) # SYN / SYN+ACK if signature: if isinstance(signature, string_types): sig, _ = TCP_Signature.from_raw_sig(signature) else: raise TypeError("Unsupported signature type") else: if not p0fdb.get_base(): sigs = [] else: direction = "request" if tcp_type == 0x02 else "response" sigs = p0fdb.get_sigs_by_os(direction, osgenre, osdetails) # If IPv6 packet, remove IPv4-only signatures and vice versa sigs = [s for s in sigs if s.ip_ver == -1 or s.ip_ver == pkt.version] if not sigs: raise ValueError("No match in the p0f database") sig = random.choice(sigs) if sig.ip_ver != -1 and pkt.version != sig.ip_ver: raise ValueError("Can't convert between IPv4 and IPv6") quirks = sig.quirks if pkt.version == 4: pkt.ttl = sig.ttl - extrahops if sig.ip_opt_len != 0: # FIXME: Non-zero IPv4 options not handled warning("Unhandled IPv4 option field") else: pkt.options = [] if "df" in quirks: pkt.flags |= 0x02 # set DF flag if "id+" in quirks: if pkt.id == 0: pkt.id = random.randint(1, 2**16 - 1) else: pkt.id = 0 else: pkt.flags &= ~(0x02) # DF flag not set if "id-" in quirks: pkt.id = 0 elif pkt.id == 0: pkt.id = random.randint(1, 2**16 - 1) if "ecn" in quirks: pkt.tos |= random.randint(0x01, 0x03) pkt.flags = pkt.flags | 0x04 if "0+" in quirks else pkt.flags & ~(0x04) else: pkt.hlim = sig.ttl - extrahops if "flow" in quirks: pkt.fl = random.randint(1, 2**20 - 1) if "ecn" in quirks: pkt.tc |= random.randint(0x01, 0x03) # Take the options already set as "hints" to use in the new packet if we # can. we'll use the already-set values if they're valid integers. def int_only(val): return val if isinstance(val, integer_types) else None orig_opts = dict(tcp.options) mss_hint = int_only(orig_opts.get("MSS")) ws_hint = int_only(orig_opts.get("WScale")) ts_hint = [int_only(o) for o in orig_opts.get("Timestamp", (None, None))] options = [] for opt in sig.olayout.split(","): if opt == "mss": # MSS might have a maximum size because of WIN_TYPE_MSS if sig.win_type == WIN_TYPE_MSS: maxmss = (2**16 - 1) // sig.win else: maxmss = (2**16 - 1) if sig.mss == -1: # wildcard mss if mss_hint and 0 <= mss_hint <= maxmss: options.append(("MSS", mss_hint)) else: # invalid hint, generate new value options.append(("MSS", random.randint(100, maxmss))) else: options.append(("MSS", sig.mss)) elif opt == "ws": if sig.wscale == -1: # wildcard wscale maxws = 2**8 if "exws" in quirks: # wscale > 14 if ws_hint and 14 < ws_hint < maxws: options.append(("WScale", ws_hint)) else: # invalid hint, generate new value > 14 options.append( ("WScale", random.randint(15, maxws - 1))) # noqa: E501 else: if ws_hint and 0 <= ws_hint < maxws: options.append(("WScale", ws_hint)) else: # invalid hint, generate new value options.append(("WScale", RandByte())) else: options.append(("WScale", sig.wscale)) elif opt == "ts": ts1, ts2 = ts_hint if "ts1-" in quirks: # own timestamp specified as zero ts1 = 0 elif uptime is not None: # if specified uptime, override ts1 = uptime elif ts1 is None or not (0 < ts1 < 2**32): # invalid hint ts1 = random.randint(120, 100 * 60 * 60 * 24 * 365) # non-zero peer timestamp on initial SYN if "ts2+" in quirks and tcp_type == 0x02: if ts2 is None or not (0 < ts2 < 2**32): # invalid hint ts2 = random.randint(1, 2**32 - 1) else: ts2 = 0 options.append(("Timestamp", (ts1, ts2))) elif opt == "nop": options.append(("NOP", None)) elif opt == "sok": options.append(("SAckOK", "")) elif opt[:3] == "eol": options.append(("EOL", None)) # FIXME: opt+ quirk not handled if "opt+" in quirks: warning("Unhandled opt+ quirk") elif opt == "sack": # Randomize SAck value in range of 10 <= val <= 34 sack_len = random.choice([10, 18, 26, 34]) - 2 optstruct = "!%iI" % (sack_len // 4) rand_val = RandString(struct.calcsize(optstruct))._fix() options.append(("SAck", struct.unpack(optstruct, rand_val))) else: warning("Unhandled TCP option %s", opt) tcp.options = options if sig.win_type == WIN_TYPE_NORMAL: tcp.window = sig.win elif sig.win_type == WIN_TYPE_MSS: mss = [x for x in options if x[0] == "MSS"] if not mss: raise ValueError( "TCP window value requires MSS, and MSS option not set" ) # noqa: E501 tcp.window = mss[0][1] * sig.win elif sig.win_type == WIN_TYPE_MOD: tcp.window = sig.win * random.randint(1, (2**16 - 1) // sig.win) elif sig.win_type == WIN_TYPE_MTU: tcp.window = mtu * sig.win elif sig.win_type == WIN_TYPE_ANY: tcp.window = RandShort() else: warning("Unhandled window size specification") if "seq-" in quirks: tcp.seq = 0 elif tcp.seq == 0: tcp.seq = random.randint(1, 2**32 - 1) if "ack+" in quirks: tcp.flags &= ~(0x10) # ACK flag not set if tcp.ack == 0: tcp.ack = random.randint(1, 2**32 - 1) elif "ack-" in quirks: tcp.flags |= 0x10 # ACK flag set tcp.ack = 0 if "uptr+" in quirks: tcp.flags &= ~(0x020) # URG flag not set if tcp.urgptr == 0: tcp.urgptr = random.randint(1, 2**16 - 1) elif "urgf+" in quirks: tcp.flags |= 0x020 # URG flag used tcp.flags = tcp.flags | 0x08 if "pushf+" in quirks else tcp.flags & ~(0x08) if sig.pay_class: # signature has payload if not tcp.payload: pkt /= conf.raw_layer(load=RandString(random.randint(1, 10))) else: tcp.payload = NoPayload() return pkt
def UDPFlood(ipDestination): packet = IP(dst=ipDestination) / UDP(dport=20) / (config.LONG_PAYLOAD * RandByte()) return packet