Generator.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. from scapy.packet import Raw
  2. import numpy.random as random2
  3. import random
  4. import string
  5. from numpy.random import bytes
  6. from random import getrandbits
  7. from scapy.layers.inet import IP, Ether, UDP, TCP
  8. from scapy.packet import Raw
  9. from Attack.MembersMgmtCommAttack import MessageType
  10. from . import IPv4 as ip
  11. '''PaddingGenerator
  12. '''
  13. def add_padding(packet, bytes_padding = 0, user_padding=True, rnd = False):
  14. '''
  15. Adds padding to a packet with the given amount of bytes, but a maximum of 100 bytes.
  16. :param packet: the packet that will be extended with the additional payload
  17. :param bytes_padding: the amount of bytes that will be appended to the packet
  18. :param user_padding: true, if the function add_padding is called from another class and the user
  19. sets the padding manually
  20. :param rnd: adds a random padding betwing 0 and bytes_adding, if true
  21. :return: the initial packet, extended with the wanted amount of bytes of padding
  22. '''
  23. if(user_padding and bytes_padding > 100):
  24. bytes_padding = 100
  25. if (rnd is True):
  26. r = int(round(bytes_padding / 4)) #sets bytes_padding to any number between 0 and bytes_padding
  27. bytes_padding = random2.random_integers(0, r) * 4 #, that's dividable by 4
  28. payload = generate_payload(bytes_padding)
  29. packet[Raw].load += Raw(load=payload).load
  30. return packet
  31. def equal_length(list_of_packets, length = 0, padding = 0):
  32. '''
  33. Equals the length of a given set of packets on the given length. If the given length is smaller than the largest
  34. packet, all the other packets are extended to the largest packet's length.
  35. :param list_of_packets: The given set of packet.
  36. :param length: The length each packet should have.
  37. :return: The set of extended packets.
  38. '''
  39. largest_packet = length
  40. for packet in list_of_packets:
  41. packet_length = len(packet)
  42. if(packet_length > largest_packet):
  43. largest_packet = packet_length
  44. for packet in list_of_packets:
  45. bytes_padding = largest_packet - len(packet)
  46. if(bytes_padding > 0):
  47. add_padding(packet, bytes_padding, False, False)
  48. add_padding(packet, padding, False, True)
  49. return list_of_packets
  50. '''PayloadGenerator
  51. '''
  52. def generate_payload(size:int=0):
  53. """
  54. Generates a payload of random bytes of the given amount
  55. :param size: number of generated bytes
  56. :return: the generated payload
  57. """
  58. payload = bytes(size)
  59. return payload
  60. '''PortGenerator
  61. '''
  62. def gen_random_server_port(offset: int=2199):
  63. """
  64. Generates a valid random first and last character for a bots hostname
  65. and computes a port from these two characters.
  66. The default offset is chosen from a Sality implementation in 2011
  67. """
  68. firstLetter = random.choice(string.ascii_letters);
  69. lastLetter = random.choice(string.ascii_letters + string.digits);
  70. return (offset + ord(firstLetter) * ord(lastLetter));
  71. '''MacAddressGenerator
  72. '''
  73. class MacAddressGenerator:
  74. def __init__(self, include_broadcast_macs=False, include_virtual_macs=False):
  75. self.broadcast = include_broadcast_macs
  76. self.virtual = include_virtual_macs
  77. self.generated = set()
  78. def random_mac(self) -> str:
  79. while True:
  80. mac = self._random_mac()
  81. if mac not in self.generated:
  82. self.generated.add(mac)
  83. return mac
  84. def clear(self):
  85. self.generated.clear()
  86. def generates_broadcast_macs(self) -> bool:
  87. return self.broadcast
  88. def generates_virtual_macs(self) -> bool:
  89. return self.virtual
  90. def set_broadcast_generation(self, broadcast: bool):
  91. self.broadcast = broadcast
  92. def set_virtual_generation(self, virtual: bool):
  93. self.virtual = virtual
  94. def _random_mac(self) -> str:
  95. mac_bytes = bytearray(getrandbits(8) for i in range(6))
  96. if not self.broadcast:
  97. mac_bytes[0] &= ~1 # clear the first bytes' first bit
  98. if not self.virtual:
  99. mac_bytes[0] &= ~2 # clear the first bytes' second bit
  100. return ":".join("%02X" % b for b in mac_bytes)
  101. '''PacketGenerator
  102. '''
  103. class PacketGenerator():
  104. """
  105. Creates packets, based on the set protocol
  106. """
  107. def __init__(self, protocol="udp"):
  108. """
  109. Creates a new Packet_Generator Object
  110. :param protocol: the protocol of the packets to be created, udp or tcp
  111. """
  112. super(PacketGenerator, self).__init__()
  113. self.protocol = protocol
  114. def generate_packet(self, ip_src: str = "192.168.64.32", ip_dst: str = "192.168.64.48",
  115. mac_src: str = "56:6D:D9:BC:70:1C",
  116. mac_dst: str = "F4:2B:95:B3:0E:1A", port_src: int = 1337, port_dst: int = 6442, ttl: int = 64,
  117. tcpflags: str = "S", payload: str = ""):
  118. """
  119. Creates a Packet with the specified Values for the current protocol
  120. :param ip_src: the source IP address of the IP header
  121. :param ip_dst the destination IP address of the IP header
  122. :param mac_src: the source MAC address of the MAC header
  123. :param mac_dst: the destination MAC address of the MAC header
  124. :param port_src: the source port of the header
  125. :param port_dst: the destination port of the header
  126. :param ttl: the ttl Value of the packet
  127. :param tcpflags: the TCP flags of the TCP header
  128. :param payload: the payload of the packet
  129. :return: the corresponding packet
  130. """
  131. if (self.protocol == "udp"):
  132. packet = generate_udp_packet(ip_src=ip_src, ip_dst=ip_dst, mac_src=mac_src, mac_dst=mac_dst, ttl=ttl,
  133. port_src=port_src, port_dst=port_dst, payload=payload)
  134. elif (self.protocol == "tcp"):
  135. packet = generate_tcp_packet(ip_src=ip_src, ip_dst=ip_dst, mac_src=mac_src, mac_dst=mac_dst, ttl=ttl,
  136. port_src=port_src, port_dst=port_dst, tcpflags=tcpflags, payload=payload)
  137. return packet
  138. def generate_mmcom_packet(self, ip_src: str = "192.168.64.32", ip_dst: str = "192.168.64.48",
  139. mac_src: str = "56:6D:D9:BC:70:1C",
  140. mac_dst: str = "F4:2B:95:B3:0E:1A", port_src: int = 1337, port_dst: int = 6442,
  141. tcpflags: str = "S", ttl: int = 64,
  142. message_type: MessageType = MessageType.SALITY_HELLO, neighborlist_entries: int = 1):
  143. """
  144. Creates a Packet for Members-Management-Communication with the specified Values and the current protocol
  145. :param ip_src: the source IP address of the IP header
  146. :param ip_dst the destination IP address of the IP header
  147. :param mac_src: the source MAC address of the MAC header
  148. :param mac_dst: the destination MAC address of the MAC header
  149. :param port_src: the source port of the header
  150. :param port_dst: the destination port of the header
  151. :param tcpflags: the TCP flags of the TCP header, if tcp is selected as protocol
  152. :param ttl: the ttl Value of the packet
  153. :param message_type: affects the size of the payload
  154. :param neighborlist_entries: number of entries of a Neighbourlist-reply, affects the size of the payload
  155. :return: the corresponding packet
  156. """
  157. # Determine length of the payload that has to be generated
  158. if (message_type == MessageType.SALITY_HELLO):
  159. payload_len = 0
  160. elif (message_type == MessageType.SALITY_HELLO_REPLY):
  161. payload_len = 22
  162. elif (message_type == MessageType.SALITY_NL_REQUEST):
  163. payload_len = 28
  164. elif (message_type == MessageType.SALITY_NL_REPLY):
  165. payload_len = 24 + 6 * neighborlist_entries
  166. else:
  167. payload_len = 0
  168. payload = generate_payload(payload_len)
  169. if (self.protocol == "udp"):
  170. packet = generate_udp_packet(ip_src=ip_src, ip_dst=ip_dst, mac_src=mac_src, mac_dst=mac_dst, ttl=ttl,
  171. port_src=port_src, port_dst=port_dst, payload=payload)
  172. elif (self.protocol == "tcp"):
  173. packet = generate_tcp_packet(ip_src=ip_src, ip_dst=ip_dst, mac_src=mac_src, mac_dst=mac_dst, ttl=ttl,
  174. port_src=port_src, port_dst=port_dst, tcpflags=tcpflags, payload=payload)
  175. else:
  176. print("Error: unsupported protocol for generating Packets")
  177. return packet
  178. def generate_tcp_packet(ip_src: str = "192.168.64.32", ip_dst: str = "192.168.64.48",
  179. mac_src: str = "56:6D:D9:BC:70:1C", ttl: int = 64,
  180. mac_dst: str = "F4:2B:95:B3:0E:1A", port_src: int = 1337, port_dst: int = 6442,
  181. tcpflags: str = "S", payload: str = ""):
  182. """
  183. Builds a TCP packet with the values specified by the caller.
  184. :param ip_src: the source IP address of the IP header
  185. :param ip_dst the destination IP address of the IP header
  186. :param mac_src: the source MAC address of the MAC header
  187. :param ttl: the ttl value of the packet
  188. :param mac_dst: the destination MAC address of the MAC header
  189. :param port_src: the source port of the TCP header
  190. :param port_dst: the destination port of the TCP header
  191. :param tcpflags: the TCP flags of the TCP header
  192. :param payload: the payload of the packet
  193. :return: the corresponding TCP packet
  194. """
  195. ether = Ether(src=mac_src, dst=mac_dst)
  196. ip = IP(src=ip_src, dst=ip_dst, ttl=ttl)
  197. tcp = TCP(sport=port_src, dport=port_dst, flags=tcpflags)
  198. packet = ether / ip / tcp / Raw(load=payload)
  199. return packet
  200. def generate_udp_packet(ip_src: str = "192.168.64.32", ip_dst: str = "192.168.64.48",
  201. mac_src: str = "56:6D:D9:BC:70:1C", ttl: int = 64,
  202. mac_dst: str = "F4:2B:95:B3:0E:1A", port_src: int = 1337, port_dst: int = 6442,
  203. payload: str = ""):
  204. """
  205. Builds an UDP packet with the values specified by the caller.
  206. :param ip_src: the source IP address of the IP header
  207. :param ip_dst the destination IP address of the IP header
  208. :param mac_src: the source MAC address of the MAC header
  209. :param ttl: the ttl value of the packet
  210. :param mac_dst: the destination MAC address of the MAC header
  211. :param port_src: the source port of the UDP header
  212. :param port_dst: the destination port of the UDP header
  213. :param payload: the payload of the packet
  214. :return: the corresponding UDP packet
  215. """
  216. ether = Ether(src=mac_src, dst=mac_dst)
  217. ip = IP(src=ip_src, dst=ip_dst, ttl=ttl)
  218. udp = UDP(sport=port_src, dport=port_dst)
  219. packet = ether / ip / udp / Raw(load=payload)
  220. return packet
  221. '''IPGenerator
  222. '''
  223. class IPChooser:
  224. def random_ip(self):
  225. return ip.IPAddress.from_int(random.randrange(0, 1 << 32))
  226. def size(self):
  227. return 1 << 32
  228. def __len__(self):
  229. return self.size()
  230. class IPChooserByRange(IPChooser):
  231. def __init__(self, ip_range):
  232. self.range = ip_range
  233. def random_ip(self):
  234. start = int(self.range.first_address())
  235. end = start + self.range.block_size()
  236. return ip.IPAddress.from_int(random.randrange(start, end))
  237. def size(self):
  238. return self.range.block_size()
  239. class IPChooserByList(IPChooser):
  240. def __init__(self, ips):
  241. self.ips = list(ips)
  242. if not self.ips:
  243. raise ValueError("list of ips must not be empty")
  244. def random_ip(self):
  245. return random.choice(self.ips)
  246. def size(self):
  247. return len(self.ips)
  248. class IPGenerator:
  249. def __init__(self, ip_chooser=IPChooser(), # include all ip-addresses by default (before the blacklist)
  250. include_private_ips=False, include_localhost=False,
  251. include_multicast=False, include_reserved=False,
  252. include_link_local=False, blacklist=None):
  253. self.blacklist = []
  254. self.generated_ips = set()
  255. if not include_private_ips:
  256. for segment in ip.ReservedIPBlocks.PRIVATE_IP_SEGMENTS:
  257. self.add_to_blacklist(segment)
  258. if not include_localhost:
  259. self.add_to_blacklist(ip.ReservedIPBlocks.LOCALHOST_SEGMENT)
  260. if not include_multicast:
  261. self.add_to_blacklist(ip.ReservedIPBlocks.MULTICAST_SEGMENT)
  262. if not include_reserved:
  263. self.add_to_blacklist(ip.ReservedIPBlocks.RESERVED_SEGMENT)
  264. if not include_link_local:
  265. self.add_to_blacklist(ip.ReservedIPBlocks.ZERO_CONF_SEGMENT)
  266. if blacklist:
  267. for segment in blacklist:
  268. self.add_to_blacklist(segment)
  269. self.chooser = ip_chooser
  270. @staticmethod
  271. def from_range(range, *args, **kwargs):
  272. return IPGenerator(IPChooserByRange(range), *args, **kwargs)
  273. def add_to_blacklist(self, ip_segment):
  274. if isinstance(ip_segment, ip.IPAddressBlock):
  275. self.blacklist.append(ip_segment)
  276. else:
  277. self.blacklist.append(ip.IPAddressBlock.parse(ip_segment))
  278. def random_ip(self):
  279. if len(self.generated_ips) == self.chooser.size():
  280. raise ValueError("Exhausted the space of possible ip-addresses, no new unique ip-address can be generated")
  281. while True:
  282. random_ip = self.chooser.random_ip()
  283. if not self._is_in_blacklist(random_ip) and random_ip not in self.generated_ips:
  284. self.generated_ips.add(random_ip)
  285. return str(random_ip)
  286. def clear(self, clear_blacklist=True, clear_generated_ips=True):
  287. if clear_blacklist: self.blacklist.clear()
  288. if clear_generated_ips: self.generated_ips.clear()
  289. def _is_in_blacklist(self, ip: ip.IPAddress):
  290. return any(ip in block for block in self.blacklist)
  291. class MappingIPGenerator(IPGenerator):
  292. def __init__(self, *args, **kwargs):
  293. super().__init__(self, *args, **kwargs)
  294. self.mapping = {}
  295. def clear(self, clear_generated_ips=True, *args, **kwargs):
  296. super().clear(self, clear_generated_ips=clear_generated_ips, *args, **kwargs)
  297. if clear_generated_ips:
  298. self.mapping = {}
  299. def get_mapped_ip(self, key):
  300. if key not in self.mapping:
  301. self.mapping[key] = self.random_ip()
  302. return self.mapping[key]
  303. def __getitem__(self, item):
  304. return self.get_mapped_ip(item)