blob: 0e963db1a06a3a88b2cd23bb797456d3ab57a9dd [file] [log] [blame]
## This file is part of Scapy
## See http://www.secdev.org/projects/scapy for more informations
## Copyright (C) Philippe Biondi <phil@secdev.org>
## This program is published under a GPLv2 license
"""
Fields that hold random numbers.
"""
from __future__ import absolute_import
import random,time,math
from scapy.base_classes import Net
from scapy.compat import *
from scapy.utils import corrupt_bits,corrupt_bytes
from scapy.modules.six.moves import range
####################
## Random numbers ##
####################
class RandomEnumeration:
"""iterate through a sequence in random order.
When all the values have been drawn, if forever=1, the drawing is done again.
If renewkeys=0, the draw will be in the same order, guaranteeing that the same
number will be drawn in not less than the number of integers of the sequence"""
def __init__(self, inf, sup, seed=None, forever=1, renewkeys=0):
self.forever = forever
self.renewkeys = renewkeys
self.inf = inf
self.rnd = random.Random(seed)
self.sbox_size = 256
self.top = sup-inf+1
n=0
while (1<<n) < self.top:
n += 1
self.n =n
self.fs = min(3,(n+1)//2)
self.fsmask = 2**self.fs-1
self.rounds = max(self.n,3)
self.turns = 0
self.i = 0
def __iter__(self):
return self
def next(self):
while True:
if self.turns == 0 or (self.i == 0 and self.renewkeys):
self.cnt_key = self.rnd.randint(0,2**self.n-1)
self.sbox = [self.rnd.randint(0, self.fsmask)
for _ in range(self.sbox_size)]
self.turns += 1
while self.i < 2**self.n:
ct = self.i^self.cnt_key
self.i += 1
for _ in range(self.rounds): # Unbalanced Feistel Network
lsb = ct & self.fsmask
ct >>= self.fs
lsb ^= self.sbox[ct%self.sbox_size]
ct |= lsb << (self.n-self.fs)
if ct < self.top:
return self.inf+ct
self.i = 0
if not self.forever:
raise StopIteration
__next__ = next
class VolatileValue:
def __repr__(self):
return "<%s>" % self.__class__.__name__
def __eq__(self, other):
x = self._fix()
y = other._fix() if isinstance(other, VolatileValue) else other
if not isinstance(x, type(y)):
return False
return x == y
def __getattr__(self, attr):
if attr in ["__setstate__", "__getstate__"]:
raise AttributeError(attr)
return getattr(self._fix(),attr)
def __str__(self):
return str(self._fix())
def __bytes__(self):
return raw(self._fix())
def __len__(self):
return len(self._fix())
def _fix(self):
return None
class RandField(VolatileValue):
pass
class RandNum(RandField):
"""Instances evaluate to random integers in selected range"""
min = 0
max = 0
def __init__(self, min, max):
self.min = min
self.max = max
def _fix(self):
return random.randrange(self.min, self.max+1)
def __int__(self):
return int(self._fix())
def __index__(self):
return int(self)
def __add__(self, other):
return self._fix() + other
def __radd__(self, other):
return other + self._fix()
def __sub__(self, other):
return self._fix() - other
def __rsub__(self, other):
return other - self._fix()
def __mul__(self, other):
return self._fix() * other
def __rmul__(self, other):
return other * self._fix()
def __floordiv__(self, other):
return self._fix() / other
__div__ = __floordiv__
class RandNumGamma(RandNum):
def __init__(self, alpha, beta):
self.alpha = alpha
self.beta = beta
def _fix(self):
return int(round(random.gammavariate(self.alpha, self.beta)))
class RandNumGauss(RandNum):
def __init__(self, mu, sigma):
self.mu = mu
self.sigma = sigma
def _fix(self):
return int(round(random.gauss(self.mu, self.sigma)))
class RandNumExpo(RandNum):
def __init__(self, lambd, base=0):
self.lambd = lambd
self.base = base
def _fix(self):
return self.base+int(round(random.expovariate(self.lambd)))
class RandEnum(RandNum):
"""Instances evaluate to integer sampling without replacement from the given interval"""
def __init__(self, min, max, seed=None):
self.seq = RandomEnumeration(min,max,seed)
def _fix(self):
return next(self.seq)
class RandByte(RandNum):
def __init__(self):
RandNum.__init__(self, 0, 2**8-1)
class RandSByte(RandNum):
def __init__(self):
RandNum.__init__(self, -2**7, 2**7-1)
class RandShort(RandNum):
def __init__(self):
RandNum.__init__(self, 0, 2**16-1)
class RandSShort(RandNum):
def __init__(self):
RandNum.__init__(self, -2**15, 2**15-1)
class RandInt(RandNum):
def __init__(self):
RandNum.__init__(self, 0, 2**32-1)
class RandSInt(RandNum):
def __init__(self):
RandNum.__init__(self, -2**31, 2**31-1)
class RandLong(RandNum):
def __init__(self):
RandNum.__init__(self, 0, 2**64-1)
class RandSLong(RandNum):
def __init__(self):
RandNum.__init__(self, -2**63, 2**63-1)
class RandEnumByte(RandEnum):
def __init__(self):
RandEnum.__init__(self, 0, 2**8-1)
class RandEnumSByte(RandEnum):
def __init__(self):
RandEnum.__init__(self, -2**7, 2**7-1)
class RandEnumShort(RandEnum):
def __init__(self):
RandEnum.__init__(self, 0, 2**16-1)
class RandEnumSShort(RandEnum):
def __init__(self):
RandEnum.__init__(self, -2**15, 2**15-1)
class RandEnumInt(RandEnum):
def __init__(self):
RandEnum.__init__(self, 0, 2**32-1)
class RandEnumSInt(RandEnum):
def __init__(self):
RandEnum.__init__(self, -2**31, 2**31-1)
class RandEnumLong(RandEnum):
def __init__(self):
RandEnum.__init__(self, 0, 2**64-1)
class RandEnumSLong(RandEnum):
def __init__(self):
RandEnum.__init__(self, -2**63, 2**63-1)
class RandEnumKeys(RandEnum):
"""Picks a random value from dict keys list. """
def __init__(self, enum, seed=None):
self.enum = list(enum)
self.seq = RandomEnumeration(0, len(self.enum) - 1, seed)
def _fix(self):
return self.enum[next(self.seq)]
class RandChoice(RandField):
def __init__(self, *args):
if not args:
raise TypeError("RandChoice needs at least one choice")
self._choice = args
def _fix(self):
return random.choice(self._choice)
class RandString(RandField):
def __init__(self, size=None, chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"):
if size is None:
size = RandNumExpo(0.01)
self.size = size
self.chars = chars
def _fix(self):
s = ""
for _ in range(self.size):
s += random.choice(self.chars)
return s
def __mul__(self, n):
return self._fix()*n
class RandBin(RandString):
def __init__(self, size=None):
RandString.__init__(self, size, "".join(map(chr, range(256))))
class RandTermString(RandString):
def __init__(self, size, term):
RandString.__init__(self, size, "".join(map(chr, range(1,256))))
self.term = term
def _fix(self):
return RandString._fix(self)+self.term
def __str__(self):
return str(self._fix())
def __bytes__(self):
return raw(self._fix())
class RandIP(RandString):
def __init__(self, iptemplate="0.0.0.0/0"):
self.ip = Net(iptemplate)
def _fix(self):
return self.ip.choice()
class RandMAC(RandString):
def __init__(self, template="*"):
template += ":*:*:*:*:*"
template = template.split(":")
self.mac = ()
for i in range(6):
if template[i] == "*":
v = RandByte()
elif "-" in template[i]:
x,y = template[i].split("-")
v = RandNum(int(x,16), int(y,16))
else:
v = int(template[i],16)
self.mac += (v,)
def _fix(self):
return "%02x:%02x:%02x:%02x:%02x:%02x" % self.mac
class RandIP6(RandString):
def __init__(self, ip6template="**"):
self.tmpl = ip6template
self.sp = self.tmpl.split(":")
for i,v in enumerate(self.sp):
if not v or v == "**":
continue
if "-" in v:
a,b = v.split("-")
elif v == "*":
a=b=""
else:
a=b=v
if not a:
a = "0"
if not b:
b = "ffff"
if a==b:
self.sp[i] = int(a,16)
else:
self.sp[i] = RandNum(int(a,16), int(b,16))
self.variable = "" in self.sp
self.multi = self.sp.count("**")
def _fix(self):
done = 0
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)
class RandOID(RandString):
def __init__(self, fmt=None, depth=RandNumExpo(0.1), idnum=RandNumExpo(0.01)):
self.ori_fmt = fmt
if fmt is not None:
fmt = fmt.split(".")
for i in range(len(fmt)):
if "-" in fmt[i]:
fmt[i] = tuple(map(int, fmt[i].split("-")))
self.fmt = fmt
self.depth = depth
self.idnum = idnum
def __repr__(self):
if self.ori_fmt is None:
return "<%s>" % self.__class__.__name__
else:
return "<%s [%s]>" % (self.__class__.__name__, self.ori_fmt)
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)
class RandRegExp(RandField):
def __init__(self, regexp, lambda_=0.3,):
self._regexp = regexp
self._lambda = lambda_
@staticmethod
def choice_expand(s): #XXX does not support special sets like (ex ':alnum:')
m = ""
invert = s and s[0] == "^"
while True:
p = s.find("-")
if p < 0:
break
if p == 0 or p == len(s)-1:
m = "-"
if p:
s = s[:-1]
else:
s = s[1:]
else:
c1 = s[p-1]
c2 = s[p+1]
rng = "".join(map(chr, range(ord(c1), ord(c2)+1)))
s = s[:p-1]+rng+s[p+1:]
res = m+s
if invert:
res = "".join(chr(x) for x in range(256) if chr(x) not in res)
return res
@staticmethod
def stack_fix(lst, index):
r = ""
mul = 1
for e in lst:
if isinstance(e, list):
if mul != 1:
mul = mul-1
r += RandRegExp.stack_fix(e[1:]*mul, index)
# only the last iteration should be kept for back reference
f = RandRegExp.stack_fix(e[1:], index)
for i,idx in enumerate(index):
if e is idx:
index[i] = f
r += f
mul = 1
elif isinstance(e, tuple):
kind,val = e
if kind == "cite":
r += index[val-1]
elif kind == "repeat":
mul = val
elif kind == "choice":
if mul == 1:
c = random.choice(val)
r += RandRegExp.stack_fix(c[1:], index)
else:
r += RandRegExp.stack_fix([e]*mul, index)
mul = 1
else:
if mul != 1:
r += RandRegExp.stack_fix([e]*mul, index)
mul = 1
else:
r += str(e)
return r
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))
elif c == '*':
e = current.pop()
current.append([current]+[e]*int(random.expovariate(self._lambda)))
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)
def __repr__(self):
return "<%s [%r]>" % (self.__class__.__name__, self._regexp)
class RandSingularity(RandChoice):
pass
class RandSingNum(RandSingularity):
@staticmethod
def make_power_of_two(end):
sign = 1
if end == 0:
end = 1
if end < 0:
end = -end
sign = -1
end_n = int(math.log(end)/math.log(2))+1
return {sign*2**i for i in range(end_n)}
def __init__(self, mn, mx):
sing = {0, mn, mx, int((mn+mx)/2)}
sing |= self.make_power_of_two(mn)
sing |= self.make_power_of_two(mx)
for i in sing.copy():
sing.add(i+1)
sing.add(i-1)
for i in sing.copy():
if not mn <= i <= mx:
sing.remove(i)
self._choice = list(sing)
self._choice.sort()
class RandSingByte(RandSingNum):
def __init__(self):
RandSingNum.__init__(self, 0, 2**8-1)
class RandSingSByte(RandSingNum):
def __init__(self):
RandSingNum.__init__(self, -2**7, 2**7-1)
class RandSingShort(RandSingNum):
def __init__(self):
RandSingNum.__init__(self, 0, 2**16-1)
class RandSingSShort(RandSingNum):
def __init__(self):
RandSingNum.__init__(self, -2**15, 2**15-1)
class RandSingInt(RandSingNum):
def __init__(self):
RandSingNum.__init__(self, 0, 2**32-1)
class RandSingSInt(RandSingNum):
def __init__(self):
RandSingNum.__init__(self, -2**31, 2**31-1)
class RandSingLong(RandSingNum):
def __init__(self):
RandSingNum.__init__(self, 0, 2**64-1)
class RandSingSLong(RandSingNum):
def __init__(self):
RandSingNum.__init__(self, -2**63, 2**63-1)
class RandSingString(RandSingularity):
def __init__(self):
self._choice = [ "",
"%x",
"%%",
"%s",
"%i",
"%n",
"%x%x%x%x%x%x%x%x%x",
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
"%",
"%%%",
"A"*4096,
b"\x00"*4096,
b"\xff"*4096,
b"\x7f"*4096,
b"\x80"*4096,
" "*4096,
"\\"*4096,
"("*4096,
"../"*1024,
"/"*1024,
"${HOME}"*512,
" or 1=1 --",
"' or 1=1 --",
'" or 1=1 --',
" or 1=1; #",
"' or 1=1; #",
'" or 1=1; #',
";reboot;",
"$(reboot)",
"`reboot`",
"index.php%00",
b"\x00",
"%00",
"\\",
"../../../../../../../../../../../../../../../../../etc/passwd",
"%2e%2e%2f" * 20 + "etc/passwd",
"%252e%252e%252f" * 20 + "boot.ini",
"..%c0%af" * 20 + "etc/passwd",
"..%c0%af" * 20 + "boot.ini",
"//etc/passwd",
r"..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\boot.ini",
"AUX:",
"CLOCK$",
"COM:",
"CON:",
"LPT:",
"LST:",
"NUL:",
"CON:",
r"C:\CON\CON",
r"C:\boot.ini",
r"\\myserver\share",
"foo.exe:",
"foo.exe\\", ]
def __str__(self):
return str(self._fix())
def __bytes__(self):
return raw(self._fix())
class RandPool(RandField):
def __init__(self, *args):
"""Each parameter is a volatile object or a couple (volatile object, weight)"""
pool = []
for p in args:
w = 1
if isinstance(p, tuple):
p,w = p
pool += [p]*w
self._pool = pool
def _fix(self):
r = random.choice(self._pool)
return r._fix()
# Automatic timestamp
class AutoTime(VolatileValue):
def __init__(self, base=None):
if base == None:
self.diff = 0
else:
self.diff = time.time()-base
def _fix(self):
return time.time()-self.diff
class IntAutoTime(AutoTime):
def _fix(self):
return int(time.time()-self.diff)
class ZuluTime(AutoTime):
def __init__(self, diff=0):
self.diff = diff
def _fix(self):
return time.strftime("%y%m%d%H%M%SZ",
time.gmtime(time.time() + self.diff))
class GeneralizedTime(AutoTime):
def __init__(self, diff=0):
self.diff = diff
def _fix(self):
return time.strftime("%Y%m%d%H%M%SZ",
time.gmtime(time.time() + self.diff))
class DelayedEval(VolatileValue):
""" Example of usage: DelayedEval("time.time()") """
def __init__(self, expr):
self.expr = expr
def _fix(self):
return eval(self.expr)
class IncrementalValue(VolatileValue):
def __init__(self, start=0, step=1, restart=-1):
self.start = self.val = start
self.step = step
self.restart = restart
def _fix(self):
v = self.val
if self.val == self.restart :
self.val = self.start
else:
self.val += self.step
return v
class CorruptedBytes(VolatileValue):
def __init__(self, s, p=0.01, n=None):
self.s = s
self.p = p
self.n = n
def _fix(self):
return corrupt_bytes(self.s, self.p, self.n)
class CorruptedBits(CorruptedBytes):
def _fix(self):
return corrupt_bits(self.s, self.p, self.n)