1# This file is part of Scapy 2# See http://www.secdev.org/projects/scapy for more information 3# Copyright (C) Philippe Biondi <phil@secdev.org> 4# Copyright (C) Michael Farrell <micolous+git@gmail.com> 5# Copyright (C) Gauthier Sebaux 6# This program is published under a GPLv2 license 7 8""" 9Fields that hold random numbers. 10""" 11 12from __future__ import absolute_import 13import copy 14import random 15import time 16import math 17import re 18import uuid 19import struct 20 21from scapy.base_classes import Net 22from scapy.compat import bytes_encode, chb, plain_str 23from scapy.utils import corrupt_bits, corrupt_bytes 24from scapy.modules.six.moves import range 25 26#################### 27# Random numbers # 28#################### 29 30 31class RandomEnumeration: 32 """iterate through a sequence in random order. 33 When all the values have been drawn, if forever=1, the drawing is done again. # noqa: E501 34 If renewkeys=0, the draw will be in the same order, guaranteeing that the same # noqa: E501 35 number will be drawn in not less than the number of integers of the sequence""" # noqa: E501 36 37 def __init__(self, inf, sup, seed=None, forever=1, renewkeys=0): 38 self.forever = forever 39 self.renewkeys = renewkeys 40 self.inf = inf 41 self.rnd = random.Random(seed) 42 self.sbox_size = 256 43 44 self.top = sup - inf + 1 45 46 n = 0 47 while (1 << n) < self.top: 48 n += 1 49 self.n = n 50 51 self.fs = min(3, (n + 1) // 2) 52 self.fsmask = 2**self.fs - 1 53 self.rounds = max(self.n, 3) 54 self.turns = 0 55 self.i = 0 56 57 def __iter__(self): 58 return self 59 60 def next(self): 61 while True: 62 if self.turns == 0 or (self.i == 0 and self.renewkeys): 63 self.cnt_key = self.rnd.randint(0, 2**self.n - 1) 64 self.sbox = [self.rnd.randint(0, self.fsmask) 65 for _ in range(self.sbox_size)] 66 self.turns += 1 67 while self.i < 2**self.n: 68 ct = self.i ^ self.cnt_key 69 self.i += 1 70 for _ in range(self.rounds): # Unbalanced Feistel Network 71 lsb = ct & self.fsmask 72 ct >>= self.fs 73 lsb ^= self.sbox[ct % self.sbox_size] 74 ct |= lsb << (self.n - self.fs) 75 76 if ct < self.top: 77 return self.inf + ct 78 self.i = 0 79 if not self.forever: 80 raise StopIteration 81 __next__ = next 82 83 84class VolatileValue(object): 85 def __repr__(self): 86 return "<%s>" % self.__class__.__name__ 87 88 def _command_args(self): 89 return '' 90 91 def command(self): 92 return "%s(%s)" % (self.__class__.__name__, self._command_args()) 93 94 def __eq__(self, other): 95 x = self._fix() 96 y = other._fix() if isinstance(other, VolatileValue) else other 97 if not isinstance(x, type(y)): 98 return False 99 return x == y 100 101 def __ne__(self, other): 102 # Python 2.7 compat 103 return not self == other 104 105 __hash__ = None 106 107 def __getattr__(self, attr): 108 if attr in ["__setstate__", "__getstate__"]: 109 raise AttributeError(attr) 110 return getattr(self._fix(), attr) 111 112 def __str__(self): 113 return str(self._fix()) 114 115 def __bytes__(self): 116 return bytes_encode(self._fix()) 117 118 def __len__(self): 119 return len(self._fix()) 120 121 def copy(self): 122 return copy.copy(self) 123 124 def _fix(self): 125 return None 126 127 128class RandField(VolatileValue): 129 pass 130 131 132class _RandNumeral(RandField): 133 """Implements integer management in RandField""" 134 135 def __int__(self): 136 return int(self._fix()) 137 138 def __index__(self): 139 return int(self) 140 141 def __nonzero__(self): 142 return bool(self._fix()) 143 __bool__ = __nonzero__ 144 145 def __add__(self, other): 146 return self._fix() + other 147 148 def __radd__(self, other): 149 return other + self._fix() 150 151 def __sub__(self, other): 152 return self._fix() - other 153 154 def __rsub__(self, other): 155 return other - self._fix() 156 157 def __mul__(self, other): 158 return self._fix() * other 159 160 def __rmul__(self, other): 161 return other * self._fix() 162 163 def __floordiv__(self, other): 164 return self._fix() / other 165 __div__ = __floordiv__ 166 167 def __lt__(self, other): 168 return self._fix() < other 169 170 def __le__(self, other): 171 return self._fix() <= other 172 173 def __ge__(self, other): 174 return self._fix() >= other 175 176 def __gt__(self, other): 177 return self._fix() > other 178 179 def __lshift__(self, other): 180 return self._fix() << other 181 182 def __rshift__(self, other): 183 return self._fix() >> other 184 185 def __and__(self, other): 186 return self._fix() & other 187 188 def __rand__(self, other): 189 return other & self._fix() 190 191 def __or__(self, other): 192 return self._fix() | other 193 194 def __ror__(self, other): 195 return other | self._fix() 196 197 198class RandNum(_RandNumeral): 199 """Instances evaluate to random integers in selected range""" 200 min = 0 201 max = 0 202 203 def __init__(self, min, max): 204 self.min = min 205 self.max = max 206 207 def _command_args(self): 208 if self.__class__.__name__ == 'RandNum': 209 return "min=%r, max=%r" % (self.min, self.max) 210 return super(RandNum, self)._command_args() 211 212 def _fix(self): 213 return random.randrange(self.min, self.max + 1) 214 215 216class RandFloat(RandNum): 217 def _fix(self): 218 return random.uniform(self.min, self.max) 219 220 221class RandBinFloat(RandNum): 222 def _fix(self): 223 return struct.unpack("!f", bytes(RandBin(4)))[0] 224 225 226class RandNumGamma(_RandNumeral): 227 def __init__(self, alpha, beta): 228 self.alpha = alpha 229 self.beta = beta 230 231 def _command_args(self): 232 return "alpha=%r, beta=%r" % (self.alpha, self.beta) 233 234 def _fix(self): 235 return int(round(random.gammavariate(self.alpha, self.beta))) 236 237 238class RandNumGauss(_RandNumeral): 239 def __init__(self, mu, sigma): 240 self.mu = mu 241 self.sigma = sigma 242 243 def _command_args(self): 244 return "mu=%r, sigma=%r" % (self.mu, self.sigma) 245 246 def _fix(self): 247 return int(round(random.gauss(self.mu, self.sigma))) 248 249 250class RandNumExpo(_RandNumeral): 251 def __init__(self, lambd, base=0): 252 self.lambd = lambd 253 self.base = base 254 255 def _command_args(self): 256 ret = "lambd=%r" % self.lambd 257 if self.base != 0: 258 ret += ", base=%r" % self.base 259 return ret 260 261 def _fix(self): 262 return self.base + int(round(random.expovariate(self.lambd))) 263 264 265class RandEnum(RandNum): 266 """Instances evaluate to integer sampling without replacement from the given interval""" # noqa: E501 267 268 def __init__(self, min, max, seed=None): 269 self._seed = seed 270 self.seq = RandomEnumeration(min, max, seed) 271 super(RandEnum, self).__init__(min, max) 272 273 def _command_args(self): 274 ret = "min=%r, max=%r" % (self.min, self.max) 275 if self._seed: 276 ret += ", seed=%r" % self._seed 277 return ret 278 279 def _fix(self): 280 return next(self.seq) 281 282 283class RandByte(RandNum): 284 def __init__(self): 285 RandNum.__init__(self, 0, 2**8 - 1) 286 287 288class RandSByte(RandNum): 289 def __init__(self): 290 RandNum.__init__(self, -2**7, 2**7 - 1) 291 292 293class RandShort(RandNum): 294 def __init__(self): 295 RandNum.__init__(self, 0, 2**16 - 1) 296 297 298class RandSShort(RandNum): 299 def __init__(self): 300 RandNum.__init__(self, -2**15, 2**15 - 1) 301 302 303class RandInt(RandNum): 304 def __init__(self): 305 RandNum.__init__(self, 0, 2**32 - 1) 306 307 308class RandSInt(RandNum): 309 def __init__(self): 310 RandNum.__init__(self, -2**31, 2**31 - 1) 311 312 313class RandLong(RandNum): 314 def __init__(self): 315 RandNum.__init__(self, 0, 2**64 - 1) 316 317 318class RandSLong(RandNum): 319 def __init__(self): 320 RandNum.__init__(self, -2**63, 2**63 - 1) 321 322 323class RandEnumByte(RandEnum): 324 def __init__(self): 325 RandEnum.__init__(self, 0, 2**8 - 1) 326 327 328class RandEnumSByte(RandEnum): 329 def __init__(self): 330 RandEnum.__init__(self, -2**7, 2**7 - 1) 331 332 333class RandEnumShort(RandEnum): 334 def __init__(self): 335 RandEnum.__init__(self, 0, 2**16 - 1) 336 337 338class RandEnumSShort(RandEnum): 339 def __init__(self): 340 RandEnum.__init__(self, -2**15, 2**15 - 1) 341 342 343class RandEnumInt(RandEnum): 344 def __init__(self): 345 RandEnum.__init__(self, 0, 2**32 - 1) 346 347 348class RandEnumSInt(RandEnum): 349 def __init__(self): 350 RandEnum.__init__(self, -2**31, 2**31 - 1) 351 352 353class RandEnumLong(RandEnum): 354 def __init__(self): 355 RandEnum.__init__(self, 0, 2**64 - 1) 356 357 358class RandEnumSLong(RandEnum): 359 def __init__(self): 360 RandEnum.__init__(self, -2**63, 2**63 - 1) 361 362 363class RandEnumKeys(RandEnum): 364 """Picks a random value from dict keys list. """ 365 366 def __init__(self, enum, seed=None): 367 self.enum = list(enum) 368 RandEnum.__init__(self, 0, len(self.enum) - 1, seed) 369 370 def _command_args(self): 371 # Note: only outputs the list of keys, but values are irrelevant anyway 372 ret = "enum=%r" % self.enum 373 if self._seed: 374 ret += ", seed=%r" % self._seed 375 return ret 376 377 def _fix(self): 378 return self.enum[next(self.seq)] 379 380 381class RandChoice(RandField): 382 def __init__(self, *args): 383 if not args: 384 raise TypeError("RandChoice needs at least one choice") 385 self._choice = list(args) 386 387 def _command_args(self): 388 return ", ".join(self._choice) 389 390 def _fix(self): 391 return random.choice(self._choice) 392 393 394class RandString(RandField): 395 _DEFAULT_CHARS = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" # noqa: E501 396 397 def __init__(self, size=None, chars=_DEFAULT_CHARS): 398 if size is None: 399 size = RandNumExpo(0.01) 400 self.size = size 401 self.chars = chars 402 403 def _command_args(self): 404 ret = "" 405 if isinstance(self.size, VolatileValue): 406 if self.size.lambd != 0.01 or self.size.base != 0: 407 ret += "size=%r" % self.size.command() 408 else: 409 ret += "size=%r" % self.size 410 411 if self.chars != self._DEFAULT_CHARS: 412 ret += ", chars=%r" % self.chars 413 return ret 414 415 def _fix(self): 416 s = b"" 417 for _ in range(self.size): 418 rdm_chr = random.choice(self.chars) 419 s += rdm_chr if isinstance(rdm_chr, str) else chb(rdm_chr) 420 return s 421 422 def __str__(self): 423 return plain_str(self._fix()) 424 425 def __bytes__(self): 426 return bytes_encode(self._fix()) 427 428 def __mul__(self, n): 429 return self._fix() * n 430 431 432class RandBin(RandString): 433 def __init__(self, size=None): 434 super(RandBin, self).__init__(size=size, chars=b"".join(chb(c) for c in range(256))) # noqa: E501 435 436 def _command_args(self): 437 if not isinstance(self.size, VolatileValue): 438 return "size=%r" % self.size 439 440 if isinstance(self.size, RandNumExpo) and \ 441 self.size.lambd == 0.01 and self.size.base == 0: 442 # Default size for RandString, skip 443 return "" 444 return "size=%r" % self.size.command() 445 446 447class RandTermString(RandBin): 448 def __init__(self, size, term): 449 self.term = bytes_encode(term) 450 super(RandTermString, self).__init__(size=size) 451 452 def _command_args(self): 453 return ", ".join((super(RandTermString, self)._command_args(), 454 "term=%r" % self.term)) 455 456 def _fix(self): 457 return RandBin._fix(self) + self.term 458 459 460class RandIP(RandString): 461 _DEFAULT_IPTEMPLATE = "0.0.0.0/0" 462 463 def __init__(self, iptemplate=_DEFAULT_IPTEMPLATE): 464 RandString.__init__(self) 465 self.ip = Net(iptemplate) 466 467 def _command_args(self): 468 if self.ip.repr == self._DEFAULT_IPTEMPLATE: 469 return "" 470 return "iptemplate=%r" % self.ip.repr 471 472 def _fix(self): 473 return self.ip.choice() 474 475 476class RandMAC(RandString): 477 def __init__(self, template="*"): 478 RandString.__init__(self) 479 self._template = template 480 template += ":*:*:*:*:*" 481 template = template.split(":") 482 self.mac = () 483 for i in range(6): 484 if template[i] == "*": 485 v = RandByte() 486 elif "-" in template[i]: 487 x, y = template[i].split("-") 488 v = RandNum(int(x, 16), int(y, 16)) 489 else: 490 v = int(template[i], 16) 491 self.mac += (v,) 492 493 def _command_args(self): 494 if self._template == "*": 495 return "" 496 return "template=%r" % self._template 497 498 def _fix(self): 499 return "%02x:%02x:%02x:%02x:%02x:%02x" % self.mac 500 501 502class RandIP6(RandString): 503 def __init__(self, ip6template="**"): 504 RandString.__init__(self) 505 self.tmpl = ip6template 506 self.sp = self.tmpl.split(":") 507 for i, v in enumerate(self.sp): 508 if not v or v == "**": 509 continue 510 if "-" in v: 511 a, b = v.split("-") 512 elif v == "*": 513 a = b = "" 514 else: 515 a = b = v 516 517 if not a: 518 a = "0" 519 if not b: 520 b = "ffff" 521 if a == b: 522 self.sp[i] = int(a, 16) 523 else: 524 self.sp[i] = RandNum(int(a, 16), int(b, 16)) 525 self.variable = "" in self.sp 526 self.multi = self.sp.count("**") 527 528 def _command_args(self): 529 if self.tmpl == "**": 530 return "" 531 return "ip6template=%r" % self.tmpl 532 533 def _fix(self): 534 nbm = self.multi 535 ip = [] 536 for i, n in enumerate(self.sp): 537 if n == "**": 538 nbm -= 1 539 remain = 8 - (len(self.sp) - i - 1) - len(ip) + nbm 540 if "" in self.sp: 541 remain += 1 542 if nbm or self.variable: 543 remain = random.randint(0, remain) 544 for j in range(remain): 545 ip.append("%04x" % random.randint(0, 65535)) 546 elif isinstance(n, RandNum): 547 ip.append("%04x" % n) 548 elif n == 0: 549 ip.append("0") 550 elif not n: 551 ip.append("") 552 else: 553 ip.append("%04x" % n) 554 if len(ip) == 9: 555 ip.remove("") 556 if ip[-1] == "": 557 ip[-1] = "0" 558 return ":".join(ip) 559 560 561class RandOID(RandString): 562 def __init__(self, fmt=None, depth=RandNumExpo(0.1), idnum=RandNumExpo(0.01)): # noqa: E501 563 RandString.__init__(self) 564 self.ori_fmt = fmt 565 if fmt is not None: 566 fmt = fmt.split(".") 567 for i in range(len(fmt)): 568 if "-" in fmt[i]: 569 fmt[i] = tuple(map(int, fmt[i].split("-"))) 570 self.fmt = fmt 571 self.depth = depth 572 self.idnum = idnum 573 574 def _command_args(self): 575 ret = [] 576 if self.fmt: 577 ret.append("fmt=%r" % self.ori_fmt) 578 579 if not isinstance(self.depth, VolatileValue): 580 ret.append("depth=%r" % self.depth) 581 elif not isinstance(self.depth, RandNumExpo) or \ 582 self.depth.lambd != 0.1 or self.depth.base != 0: 583 ret.append("depth=%s" % self.depth.command()) 584 585 if not isinstance(self.idnum, VolatileValue): 586 ret.append("idnum=%r" % self.idnum) 587 elif not isinstance(self.idnum, RandNumExpo) or \ 588 self.idnum.lambd != 0.01 or self.idnum.base != 0: 589 ret.append("idnum=%s" % self.idnum.command()) 590 591 return ", ".join(ret) 592 593 def __repr__(self): 594 if self.ori_fmt is None: 595 return "<%s>" % self.__class__.__name__ 596 else: 597 return "<%s [%s]>" % (self.__class__.__name__, self.ori_fmt) 598 599 def _fix(self): 600 if self.fmt is None: 601 return ".".join(str(self.idnum) for _ in range(1 + self.depth)) 602 else: 603 oid = [] 604 for i in self.fmt: 605 if i == "*": 606 oid.append(str(self.idnum)) 607 elif i == "**": 608 oid += [str(self.idnum) for i in range(1 + self.depth)] 609 elif isinstance(i, tuple): 610 oid.append(str(random.randrange(*i))) 611 else: 612 oid.append(i) 613 return ".".join(oid) 614 615 616class RandRegExp(RandField): 617 def __init__(self, regexp, lambda_=0.3,): 618 self._regexp = regexp 619 self._lambda = lambda_ 620 621 def _command_args(self): 622 ret = "regexp=%r" % self._regexp 623 if self._lambda != 0.3: 624 ret += ", lambda_=%r" % self._lambda 625 return ret 626 627 special_sets = { 628 "[:alnum:]": "[a-zA-Z0-9]", 629 "[:alpha:]": "[a-zA-Z]", 630 "[:ascii:]": "[\x00-\x7F]", 631 "[:blank:]": "[ \t]", 632 "[:cntrl:]": "[\x00-\x1F\x7F]", 633 "[:digit:]": "[0-9]", 634 "[:graph:]": "[\x21-\x7E]", 635 "[:lower:]": "[a-z]", 636 "[:print:]": "[\x20-\x7E]", 637 "[:punct:]": "[!\"\\#$%&'()*+,\\-./:;<=>?@\\[\\\\\\]^_{|}~]", 638 "[:space:]": "[ \t\r\n\v\f]", 639 "[:upper:]": "[A-Z]", 640 "[:word:]": "[A-Za-z0-9_]", 641 "[:xdigit:]": "[A-Fa-f0-9]", 642 } 643 644 @staticmethod 645 def choice_expand(s): 646 m = "" 647 invert = s and s[0] == "^" 648 while True: 649 p = s.find("-") 650 if p < 0: 651 break 652 if p == 0 or p == len(s) - 1: 653 m = "-" 654 if p: 655 s = s[:-1] 656 else: 657 s = s[1:] 658 else: 659 c1 = s[p - 1] 660 c2 = s[p + 1] 661 rng = "".join(map(chr, range(ord(c1), ord(c2) + 1))) 662 s = s[:p - 1] + rng + s[p + 1:] 663 res = m + s 664 if invert: 665 res = "".join(chr(x) for x in range(256) if chr(x) not in res) 666 return res 667 668 @staticmethod 669 def stack_fix(lst, index): 670 r = "" 671 mul = 1 672 for e in lst: 673 if isinstance(e, list): 674 if mul != 1: 675 mul = mul - 1 676 r += RandRegExp.stack_fix(e[1:] * mul, index) 677 # only the last iteration should be kept for back reference 678 f = RandRegExp.stack_fix(e[1:], index) 679 for i, idx in enumerate(index): 680 if e is idx: 681 index[i] = f 682 r += f 683 mul = 1 684 elif isinstance(e, tuple): 685 kind, val = e 686 if kind == "cite": 687 r += index[val - 1] 688 elif kind == "repeat": 689 mul = val 690 691 elif kind == "choice": 692 if mul == 1: 693 c = random.choice(val) 694 r += RandRegExp.stack_fix(c[1:], index) 695 else: 696 r += RandRegExp.stack_fix([e] * mul, index) 697 mul = 1 698 else: 699 if mul != 1: 700 r += RandRegExp.stack_fix([e] * mul, index) 701 mul = 1 702 else: 703 r += str(e) 704 return r 705 706 def _fix(self): 707 stack = [None] 708 index = [] 709 current = stack 710 i = 0 711 regexp = self._regexp 712 for k, v in self.special_sets.items(): 713 regexp = regexp.replace(k, v) 714 ln = len(regexp) 715 interp = True 716 while i < ln: 717 c = regexp[i] 718 i += 1 719 720 if c == '(': 721 current = [current] 722 current[0].append(current) 723 elif c == '|': 724 p = current[0] 725 ch = p[-1] 726 if not isinstance(ch, tuple): 727 ch = ("choice", [current]) 728 p[-1] = ch 729 else: 730 ch[1].append(current) 731 current = [p] 732 elif c == ')': 733 ch = current[0][-1] 734 if isinstance(ch, tuple): 735 ch[1].append(current) 736 index.append(current) 737 current = current[0] 738 elif c == '[' or c == '{': 739 current = [current] 740 current[0].append(current) 741 interp = False 742 elif c == ']': 743 current = current[0] 744 choice = RandRegExp.choice_expand("".join(current.pop()[1:])) 745 current.append(RandChoice(*list(choice))) 746 interp = True 747 elif c == '}': 748 current = current[0] 749 num = "".join(current.pop()[1:]) 750 e = current.pop() 751 if "," not in num: 752 n = int(num) 753 current.append([current] + [e] * n) 754 else: 755 num_min, num_max = num.split(",") 756 if not num_min: 757 num_min = "0" 758 if num_max: 759 n = RandNum(int(num_min), int(num_max)) 760 else: 761 n = RandNumExpo(self._lambda, base=int(num_min)) 762 current.append(("repeat", n)) 763 current.append(e) 764 interp = True 765 elif c == '\\': 766 c = regexp[i] 767 if c == "s": 768 c = RandChoice(" ", "\t") 769 elif c in "0123456789": 770 c = ("cite", ord(c) - 0x30) 771 current.append(c) 772 i += 1 773 elif not interp: 774 current.append(c) 775 elif c == '+': 776 e = current.pop() 777 current.append([current] + [e] * (int(random.expovariate(self._lambda)) + 1)) # noqa: E501 778 elif c == '*': 779 e = current.pop() 780 current.append([current] + [e] * int(random.expovariate(self._lambda))) # noqa: E501 781 elif c == '?': 782 if random.randint(0, 1): 783 current.pop() 784 elif c == '.': 785 current.append(RandChoice(*[chr(x) for x in range(256)])) 786 elif c == '$' or c == '^': 787 pass 788 else: 789 current.append(c) 790 791 return RandRegExp.stack_fix(stack[1:], index) 792 793 def __repr__(self): 794 return "<%s [%r]>" % (self.__class__.__name__, self._regexp) 795 796 797class RandSingularity(RandChoice): 798 pass 799 800 801class RandSingNum(RandSingularity): 802 @staticmethod 803 def make_power_of_two(end): 804 sign = 1 805 if end == 0: 806 end = 1 807 if end < 0: 808 end = -end 809 sign = -1 810 end_n = int(math.log(end) / math.log(2)) + 1 811 return {sign * 2**i for i in range(end_n)} 812 813 def __init__(self, mn, mx): 814 self._mn = mn 815 self._mx = mx 816 sing = {0, mn, mx, int((mn + mx) / 2)} 817 sing |= self.make_power_of_two(mn) 818 sing |= self.make_power_of_two(mx) 819 for i in sing.copy(): 820 sing.add(i + 1) 821 sing.add(i - 1) 822 for i in sing.copy(): 823 if not mn <= i <= mx: 824 sing.remove(i) 825 super(RandSingNum, self).__init__(*sing) 826 self._choice.sort() 827 828 def _command_args(self): 829 if self.__class__.__name__ == 'RandSingNum': 830 return "mn=%r, mx=%r" % (self._mn, self._mx) 831 return super(RandSingNum, self)._command_args() 832 833 834class RandSingByte(RandSingNum): 835 def __init__(self): 836 RandSingNum.__init__(self, 0, 2**8 - 1) 837 838 839class RandSingSByte(RandSingNum): 840 def __init__(self): 841 RandSingNum.__init__(self, -2**7, 2**7 - 1) 842 843 844class RandSingShort(RandSingNum): 845 def __init__(self): 846 RandSingNum.__init__(self, 0, 2**16 - 1) 847 848 849class RandSingSShort(RandSingNum): 850 def __init__(self): 851 RandSingNum.__init__(self, -2**15, 2**15 - 1) 852 853 854class RandSingInt(RandSingNum): 855 def __init__(self): 856 RandSingNum.__init__(self, 0, 2**32 - 1) 857 858 859class RandSingSInt(RandSingNum): 860 def __init__(self): 861 RandSingNum.__init__(self, -2**31, 2**31 - 1) 862 863 864class RandSingLong(RandSingNum): 865 def __init__(self): 866 RandSingNum.__init__(self, 0, 2**64 - 1) 867 868 869class RandSingSLong(RandSingNum): 870 def __init__(self): 871 RandSingNum.__init__(self, -2**63, 2**63 - 1) 872 873 874class RandSingString(RandSingularity): 875 def __init__(self): 876 choices_list = ["", 877 "%x", 878 "%%", 879 "%s", 880 "%i", 881 "%n", 882 "%x%x%x%x%x%x%x%x%x", 883 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 884 "%", 885 "%%%", 886 "A" * 4096, 887 b"\x00" * 4096, 888 b"\xff" * 4096, 889 b"\x7f" * 4096, 890 b"\x80" * 4096, 891 " " * 4096, 892 "\\" * 4096, 893 "(" * 4096, 894 "../" * 1024, 895 "/" * 1024, 896 "${HOME}" * 512, 897 " or 1=1 --", 898 "' or 1=1 --", 899 '" or 1=1 --', 900 " or 1=1; #", 901 "' or 1=1; #", 902 '" or 1=1; #', 903 ";reboot;", 904 "$(reboot)", 905 "`reboot`", 906 "index.php%00", 907 b"\x00", 908 "%00", 909 "\\", 910 "../../../../../../../../../../../../../../../../../etc/passwd", # noqa: E501 911 "%2e%2e%2f" * 20 + "etc/passwd", 912 "%252e%252e%252f" * 20 + "boot.ini", 913 "..%c0%af" * 20 + "etc/passwd", 914 "..%c0%af" * 20 + "boot.ini", 915 "//etc/passwd", 916 r"..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\boot.ini", # noqa: E501 917 "AUX:", 918 "CLOCK$", 919 "COM:", 920 "CON:", 921 "LPT:", 922 "LST:", 923 "NUL:", 924 "CON:", 925 r"C:\CON\CON", 926 r"C:\boot.ini", 927 r"\\myserver\share", 928 "foo.exe:", 929 "foo.exe\\", ] 930 super(RandSingString, self).__init__(*choices_list) 931 932 def _command_args(self): 933 return "" 934 935 def __str__(self): 936 return str(self._fix()) 937 938 def __bytes__(self): 939 return bytes_encode(self._fix()) 940 941 942class RandPool(RandField): 943 def __init__(self, *args): 944 """Each parameter is a volatile object or a couple (volatile object, weight)""" # noqa: E501 945 self._args = args 946 pool = [] 947 for p in args: 948 w = 1 949 if isinstance(p, tuple): 950 p, w = p 951 pool += [p] * w 952 self._pool = pool 953 954 def _command_args(self): 955 ret = [] 956 for p in self._args: 957 if isinstance(p, tuple): 958 ret.append("(%s, %r)" % (p[0].command(), p[1])) 959 else: 960 ret.append(p.command()) 961 return ", ".join(ret) 962 963 def _fix(self): 964 r = random.choice(self._pool) 965 return r._fix() 966 967 968class RandUUID(RandField): 969 """Generates a random UUID. 970 971 By default, this generates a RFC 4122 version 4 UUID (totally random). 972 973 See Python's ``uuid`` module documentation for more information. 974 975 Args: 976 template (optional): A template to build the UUID from. Not valid with 977 any other option. 978 node (optional): A 48-bit Host ID. Only valid for version 1 (where it 979 is optional). 980 clock_seq (optional): An integer of up to 14-bits for the sequence 981 number. Only valid for version 1 (where it is 982 optional). 983 namespace: A namespace identifier, which is also a UUID. Required for 984 versions 3 and 5, must be omitted otherwise. 985 name: string, required for versions 3 and 5, must be omitted otherwise. 986 version: Version of UUID to use (1, 3, 4 or 5). If omitted, attempts to 987 guess which version to generate, defaulting to version 4 988 (totally random). 989 990 Raises: 991 ValueError: on invalid constructor arguments 992 """ 993 # This was originally scapy.contrib.dce_rpc.RandUUID. 994 995 _BASE = "([0-9a-f]{{{0}}}|\\*|[0-9a-f]{{{0}}}:[0-9a-f]{{{0}}})" 996 _REG = re.compile( 997 r"^{0}-?{1}-?{1}-?{2}{2}-?{2}{2}{2}{2}{2}{2}$".format( 998 _BASE.format(8), _BASE.format(4), _BASE.format(2) 999 ), 1000 re.I 1001 ) 1002 VERSIONS = [1, 3, 4, 5] 1003 1004 def __init__(self, template=None, node=None, clock_seq=None, 1005 namespace=None, name=None, version=None): 1006 self._template = template 1007 self._ori_version = version 1008 1009 self.uuid_template = None 1010 self.node = None 1011 self.clock_seq = None 1012 self.namespace = None 1013 self.name = None 1014 self.node = None 1015 self.version = None 1016 1017 if template: 1018 if node or clock_seq or namespace or name or version: 1019 raise ValueError("UUID template must be the only parameter, " 1020 "if specified") 1021 tmp = RandUUID._REG.match(template) 1022 if tmp: 1023 template = tmp.groups() 1024 else: 1025 # Invalid template 1026 raise ValueError("UUID template is invalid") 1027 1028 rnd_f = [RandInt] + [RandShort] * 2 + [RandByte] * 8 1029 uuid_template = [] 1030 for i, t in enumerate(template): 1031 if t == "*": 1032 val = rnd_f[i]() 1033 elif ":" in t: 1034 mini, maxi = t.split(":") 1035 val = RandNum(int(mini, 16), int(maxi, 16)) 1036 else: 1037 val = int(t, 16) 1038 uuid_template.append(val) 1039 1040 self.uuid_template = tuple(uuid_template) 1041 else: 1042 if version: 1043 if version not in RandUUID.VERSIONS: 1044 raise ValueError("version is not supported") 1045 else: 1046 self.version = version 1047 else: 1048 # No version specified, try to guess... 1049 # This could be wrong, and cause an error later! 1050 if node or clock_seq: 1051 self.version = 1 1052 elif namespace and name: 1053 self.version = 5 1054 else: 1055 # Don't know, random! 1056 self.version = 4 1057 1058 # We have a version, now do things... 1059 if self.version == 1: 1060 if namespace or name: 1061 raise ValueError("namespace and name may not be used with " 1062 "version 1") 1063 self.node = node 1064 self.clock_seq = clock_seq 1065 elif self.version in (3, 5): 1066 if node or clock_seq: 1067 raise ValueError("node and clock_seq may not be used with " 1068 "version {}".format(self.version)) 1069 1070 self.namespace = namespace 1071 self.name = name 1072 elif self.version == 4: 1073 if namespace or name or node or clock_seq: 1074 raise ValueError("node, clock_seq, node and clock_seq may " 1075 "not be used with version 4. If you " 1076 "did not specify version, you need to " 1077 "specify it explicitly.") 1078 1079 def _command_args(self): 1080 ret = [] 1081 if self._template: 1082 ret.append("template=%r" % self._template) 1083 if self.node: 1084 ret.append("node=%r" % self.node) 1085 if self.clock_seq: 1086 ret.append("clock_seq=%r" % self.clock_seq) 1087 if self.namespace: 1088 ret.append("namespace=%r" % self.namespace) 1089 if self.name: 1090 ret.append("name=%r" % self.name) 1091 if self._ori_version: 1092 ret.append("version=%r" % self._ori_version) 1093 return ", ".join(ret) 1094 1095 def _fix(self): 1096 if self.uuid_template: 1097 return uuid.UUID(("%08x%04x%04x" + ("%02x" * 8)) 1098 % self.uuid_template) 1099 elif self.version == 1: 1100 return uuid.uuid1(self.node, self.clock_seq) 1101 elif self.version == 3: 1102 return uuid.uuid3(self.namespace, self.name) 1103 elif self.version == 4: 1104 return uuid.uuid4() 1105 elif self.version == 5: 1106 return uuid.uuid5(self.namespace, self.name) 1107 else: 1108 raise ValueError("Unhandled version") 1109 1110 1111# Automatic timestamp 1112 1113 1114class AutoTime(_RandNumeral): 1115 def __init__(self, base=None, diff=None): 1116 self._base = base 1117 self._ori_diff = diff 1118 1119 if diff is not None: 1120 self.diff = diff 1121 elif base is None: 1122 self.diff = 0 1123 else: 1124 self.diff = time.time() - base 1125 1126 def _command_args(self): 1127 ret = [] 1128 if self._base: 1129 ret.append("base=%r" % self._base) 1130 if self._ori_diff: 1131 ret.append("diff=%r" % self._ori_diff) 1132 return ", ".join(ret) 1133 1134 def _fix(self): 1135 return time.time() - self.diff 1136 1137 1138class IntAutoTime(AutoTime): 1139 def _fix(self): 1140 return int(time.time() - self.diff) 1141 1142 1143class ZuluTime(AutoTime): 1144 def __init__(self, diff=0): 1145 super(ZuluTime, self).__init__(diff=diff) 1146 1147 def _fix(self): 1148 return time.strftime("%y%m%d%H%M%SZ", 1149 time.gmtime(time.time() + self.diff)) 1150 1151 1152class GeneralizedTime(AutoTime): 1153 def __init__(self, diff=0): 1154 super(GeneralizedTime, self).__init__(diff=diff) 1155 1156 def _fix(self): 1157 return time.strftime("%Y%m%d%H%M%SZ", 1158 time.gmtime(time.time() + self.diff)) 1159 1160 1161class DelayedEval(VolatileValue): 1162 """ Example of usage: DelayedEval("time.time()") """ 1163 1164 def __init__(self, expr): 1165 self.expr = expr 1166 1167 def _command_args(self): 1168 return "expr=%r" % self.expr 1169 1170 def _fix(self): 1171 return eval(self.expr) 1172 1173 1174class IncrementalValue(VolatileValue): 1175 def __init__(self, start=0, step=1, restart=-1): 1176 self.start = self.val = start 1177 self.step = step 1178 self.restart = restart 1179 1180 def _command_args(self): 1181 ret = [] 1182 if self.start: 1183 ret.append("start=%r" % self.start) 1184 if self.step != 1: 1185 ret.append("step=%r" % self.step) 1186 if self.restart != -1: 1187 ret.append("restart=%r" % self.restart) 1188 return ", ".join(ret) 1189 1190 def _fix(self): 1191 v = self.val 1192 if self.val == self.restart: 1193 self.val = self.start 1194 else: 1195 self.val += self.step 1196 return v 1197 1198 1199class CorruptedBytes(VolatileValue): 1200 def __init__(self, s, p=0.01, n=None): 1201 self.s = s 1202 self.p = p 1203 self.n = n 1204 1205 def _command_args(self): 1206 ret = [] 1207 ret.append("s=%r" % self.s) 1208 if self.p != 0.01: 1209 ret.append("p=%r" % self.p) 1210 if self.n: 1211 ret.append("n=%r" % self.n) 1212 return ", ".join(ret) 1213 1214 def _fix(self): 1215 return corrupt_bytes(self.s, self.p, self.n) 1216 1217 1218class CorruptedBits(CorruptedBytes): 1219 def _fix(self): 1220 return corrupt_bits(self.s, self.p, self.n) 1221