bbot 2.1.0.5004rc0__py3-none-any.whl → 2.1.0.5021rc0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
bbot/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # version placeholder (replaced by poetry-dynamic-versioning)
2
- __version__ = "v2.1.0.5004rc"
2
+ __version__ = "v2.1.0.5021rc"
3
3
 
4
4
  from .scanner import Scanner, Preset
bbot/core/event/base.py CHANGED
@@ -25,6 +25,7 @@ from bbot.core.helpers import (
25
25
  is_domain,
26
26
  is_subdomain,
27
27
  is_ip,
28
+ is_ip_type,
28
29
  is_ptr,
29
30
  is_uri,
30
31
  url_depth,
@@ -352,6 +353,12 @@ class BaseEvent:
352
353
  return 80
353
354
  return self._port
354
355
 
356
+ @property
357
+ def netloc(self):
358
+ if self.host and is_ip_type(self.host, network=False):
359
+ return make_netloc(self.host, self.port)
360
+ return None
361
+
355
362
  @property
356
363
  def host_stem(self):
357
364
  """
@@ -741,7 +748,7 @@ class BaseEvent:
741
748
  """
742
749
  j = dict()
743
750
  # type, ID, scope description
744
- for i in ("type", "id", "uuid", "scope_description"):
751
+ for i in ("type", "id", "uuid", "scope_description", "netloc"):
745
752
  v = getattr(self, i, "")
746
753
  if v:
747
754
  j.update({i: str(v)})
@@ -760,6 +767,8 @@ class BaseEvent:
760
767
  j["host"] = str(self.host)
761
768
  j["resolved_hosts"] = sorted(str(h) for h in self.resolved_hosts)
762
769
  j["dns_children"] = {k: list(v) for k, v in self.dns_children.items()}
770
+ if isinstance(self.port, int):
771
+ j["port"] = self.port
763
772
  # web spider distance
764
773
  web_spider_distance = getattr(self, "web_spider_distance", None)
765
774
  if web_spider_distance is not None:
bbot/core/helpers/misc.py CHANGED
@@ -621,12 +621,13 @@ def is_ip(d, version=None):
621
621
  return False
622
622
 
623
623
 
624
- def is_ip_type(i):
624
+ def is_ip_type(i, network=None):
625
625
  """
626
626
  Checks if the given object is an instance of an IPv4 or IPv6 type from the ipaddress module.
627
627
 
628
628
  Args:
629
629
  i (ipaddress._BaseV4 or ipaddress._BaseV6): The IP object to check.
630
+ network (bool, optional): Whether to restrict the check to network types (IPv4Network or IPv6Network). Defaults to False.
630
631
 
631
632
  Returns:
632
633
  bool: True if the object is an instance of ipaddress._BaseV4 or ipaddress._BaseV6, False otherwise.
@@ -639,6 +640,12 @@ def is_ip_type(i):
639
640
  >>> is_ip_type("192.168.1.0/24")
640
641
  False
641
642
  """
643
+ if network is not None:
644
+ is_network = ipaddress._BaseNetwork in i.__class__.__mro__
645
+ if network:
646
+ return is_network
647
+ else:
648
+ return not is_network
642
649
  return ipaddress._IPAddressBase in i.__class__.__mro__
643
650
 
644
651
 
@@ -1260,7 +1267,7 @@ def gen_numbers(n, padding=2):
1260
1267
  return results
1261
1268
 
1262
1269
 
1263
- def make_netloc(host, port):
1270
+ def make_netloc(host, port=None):
1264
1271
  """Constructs a network location string from a given host and port.
1265
1272
 
1266
1273
  Args:
@@ -1289,7 +1296,7 @@ def make_netloc(host, port):
1289
1296
  if is_ip(host, version=6):
1290
1297
  host = f"[{host}]"
1291
1298
  if port is None:
1292
- return host
1299
+ return str(host)
1293
1300
  return f"{host}:{port}"
1294
1301
 
1295
1302
 
bbot/modules/base.py CHANGED
@@ -984,8 +984,11 @@ class BaseModule:
984
984
  def _outgoing_dedup_hash(self, event):
985
985
  """
986
986
  Determines the criteria for what is considered to be a duplicate event if `suppress_dupes` is True.
987
+
988
+ We take into account the `internal` attribute we don't want an internal event (which isn't distributed to output modules)
989
+ to inadvertently suppress a non-internal event.
987
990
  """
988
- return hash((event, self.name))
991
+ return hash((event, self.name, event.internal, event.always_emit))
989
992
 
990
993
  def get_per_host_hash(self, event):
991
994
  """
@@ -137,10 +137,10 @@ class Generic_XXE(BaseSubmodule):
137
137
  post_body = f"""<?xml version="1.0" encoding="ISO-8859-1"?>
138
138
  <!DOCTYPE foo [
139
139
  <!ELEMENT foo ANY >
140
- <!ENTITY % {rand_entity} SYSTEM "http://{subdomain_tag}.{self.parent_module.interactsh_domain}" >
140
+ <!ENTITY {rand_entity} SYSTEM "http://{subdomain_tag}.{self.parent_module.interactsh_domain}" >
141
141
  ]>
142
142
  <foo>&{rand_entity};</foo>"""
143
- test_url = f"{event.parsed_url.scheme}://{event.parsed_url.netloc}/"
143
+ test_url = event.parsed_url.geturl()
144
144
  r = await self.parent_module.helpers.curl(
145
145
  url=test_url, method="POST", raw_body=post_body, headers={"Content-type": "application/xml"}
146
146
  )
@@ -16,12 +16,6 @@ class DNSResolve(BaseInterceptModule):
16
16
  _name = "host"
17
17
  _type = "internal"
18
18
 
19
- def _outgoing_dedup_hash(self, event):
20
- # this exists to ensure a second, more interesting host isn't passed up
21
- # because its ugly cousin spent its one dedup token before it arrived
22
- # by removing those race conditions, this makes for more consistent results
23
- return hash((event, self.name, event.always_emit))
24
-
25
19
  @property
26
20
  def module_threads(self):
27
21
  return self.dns_config.get("threads", 25)
@@ -876,6 +876,8 @@ class excavate(BaseInternalModule, BaseInterceptModule):
876
876
  yara_rules_combined = "\n".join(self.yara_rules_dict.values())
877
877
  try:
878
878
  self.info(f"Compiling {len(self.yara_rules_dict):,} YARA rules")
879
+ for rule_name, rule_content in self.yara_rules_dict.items():
880
+ self.debug(f" - {rule_name}")
879
881
  self.yara_rules = yara.compile(source=yara_rules_combined)
880
882
  except yara.SyntaxError as e:
881
883
  self.debug(yara_rules_combined)
@@ -112,15 +112,15 @@ class speculate(BaseInternalModule):
112
112
  speculate_open_ports = self.emit_open_ports and event_in_scope_distance
113
113
 
114
114
  # URL --> OPEN_TCP_PORT
115
- if event.type == "URL" or (event.type == "URL_UNVERIFIED" and self.open_port_consumers):
115
+ event_is_url = event.type == "URL"
116
+ if event_is_url or (event.type == "URL_UNVERIFIED" and self.open_port_consumers):
116
117
  # only speculate port from a URL if it wouldn't be speculated naturally from the host
117
118
  if event.host and (event.port not in self.ports or not speculate_open_ports):
118
119
  await self.emit_event(
119
120
  self.helpers.make_netloc(event.host, event.port),
120
121
  "OPEN_TCP_PORT",
121
122
  parent=event,
122
- internal=True,
123
- quick=(event.type == "URL"),
123
+ internal=not event_is_url, # if the URL is verified, the port is definitely open
124
124
  context=f"speculated {{event.type}} from {event.type}: {{event.data}}",
125
125
  )
126
126
 
@@ -169,7 +169,6 @@ class speculate(BaseInternalModule):
169
169
  "OPEN_TCP_PORT",
170
170
  parent=event,
171
171
  internal=True,
172
- quick=True,
173
172
  context="speculated {event.type}: {event.data}",
174
173
  )
175
174
 
@@ -16,13 +16,11 @@ class shodan_dns(shodan):
16
16
 
17
17
  base_url = "https://api.shodan.io"
18
18
 
19
- async def request_url(self, query):
20
- url = f"{self.base_url}/dns/domain/{self.helpers.quote(query)}?key={{api_key}}"
21
- response = await self.api_request(url)
22
- return response
19
+ async def handle_event(self, event):
20
+ await self.handle_event_paginated(event)
23
21
 
24
- def parse_results(self, r, query):
25
- json = r.json()
26
- if json:
27
- for hostname in json.get("subdomains", []):
28
- yield f"{hostname}.{query}"
22
+ def make_url(self, query):
23
+ return f"{self.base_url}/dns/domain/{self.helpers.quote(query)}?key={{api_key}}&page={{page}}"
24
+
25
+ def parse_results(self, json, query):
26
+ return [f"{sub}.{query}" for sub in json.get("subdomains", [])]
@@ -31,6 +31,11 @@ class subdomain_enum(BaseModule):
31
31
  # "lowest_parent": dedupe by lowest parent (lowest parent of www.api.test.evilcorp.com is api.test.evilcorp.com)
32
32
  dedup_strategy = "highest_parent"
33
33
 
34
+ # how many results to request per API call
35
+ page_size = 100
36
+ # arguments to pass to api_page_iter
37
+ api_page_iter_kwargs = {}
38
+
34
39
  @property
35
40
  def source_pretty_name(self):
36
41
  return f"{self.__class__.__name__} API"
@@ -61,10 +66,31 @@ class subdomain_enum(BaseModule):
61
66
  context=f'{{module}} searched {self.source_pretty_name} for "{query}" and found {{event.type}}: {{event.data}}',
62
67
  )
63
68
 
69
+ async def handle_event_paginated(self, event):
70
+ query = self.make_query(event)
71
+ async for result_batch in self.query_paginated(query):
72
+ for hostname in set(result_batch):
73
+ try:
74
+ hostname = self.helpers.validators.validate_host(hostname)
75
+ except ValueError as e:
76
+ self.verbose(e)
77
+ continue
78
+ if hostname and hostname.endswith(f".{query}") and not hostname == event.data:
79
+ await self.emit_event(
80
+ hostname,
81
+ "DNS_NAME",
82
+ event,
83
+ abort_if=self.abort_if,
84
+ context=f'{{module}} searched {self.source_pretty_name} for "{query}" and found {{event.type}}: {{event.data}}',
85
+ )
86
+
64
87
  async def request_url(self, query):
65
- url = f"{self.base_url}/subdomains/{self.helpers.quote(query)}"
88
+ url = self.make_url(query)
66
89
  return await self.api_request(url)
67
90
 
91
+ def make_url(self, query):
92
+ return f"{self.base_url}/subdomains/{self.helpers.quote(query)}"
93
+
68
94
  def make_query(self, event):
69
95
  query = event.data
70
96
  parents = list(self.helpers.domain_parents(event.data))
@@ -86,11 +112,11 @@ class subdomain_enum(BaseModule):
86
112
  for hostname in json:
87
113
  yield hostname
88
114
 
89
- async def query(self, query, parse_fn=None, request_fn=None):
90
- if parse_fn is None:
91
- parse_fn = self.parse_results
115
+ async def query(self, query, request_fn=None, parse_fn=None):
92
116
  if request_fn is None:
93
117
  request_fn = self.request_url
118
+ if parse_fn is None:
119
+ parse_fn = self.parse_results
94
120
  try:
95
121
  response = await request_fn(query)
96
122
  if response is None:
@@ -113,6 +139,19 @@ class subdomain_enum(BaseModule):
113
139
  except Exception as e:
114
140
  self.info(f"Error retrieving results for {query}: {e}", trace=True)
115
141
 
142
+ async def query_paginated(self, query):
143
+ url = self.make_url(query)
144
+ agen = self.api_page_iter(url, page_size=self.page_size, **self.api_page_iter_kwargs)
145
+ try:
146
+ async for response in agen:
147
+ subdomains = self.parse_results(response, query)
148
+ self.verbose(f'Got {len(subdomains):,} subdomains for "{query}"')
149
+ if not subdomains:
150
+ break
151
+ yield subdomains
152
+ finally:
153
+ agen.aclose()
154
+
116
155
  async def _is_wildcard(self, query):
117
156
  rdtypes = ("A", "AAAA", "CNAME")
118
157
  if self.helpers.is_dns_name(query):
bbot/modules/trickest.py CHANGED
@@ -28,39 +28,15 @@ class Trickest(subdomain_enum_apikey):
28
28
  return url, kwargs
29
29
 
30
30
  async def handle_event(self, event):
31
- query = self.make_query(event)
32
- async for result_batch in self.query(query):
33
- for hostname in set(result_batch):
34
- try:
35
- hostname = self.helpers.validators.validate_host(hostname)
36
- except ValueError as e:
37
- self.verbose(e)
38
- continue
39
- if hostname and hostname.endswith(f".{query}") and not hostname == event.data:
40
- await self.emit_event(
41
- hostname,
42
- "DNS_NAME",
43
- event,
44
- abort_if=self.abort_if,
45
- context=f'{{module}} searched {self.source_pretty_name} for "{query}" and found {{event.type}}: {{event.data}}',
46
- )
31
+ await self.handle_event_paginated(event)
47
32
 
48
- async def query(self, query):
33
+ def make_url(self, query):
49
34
  url = f"{self.base_url}/view?q=hostname%20~%20%22.{self.helpers.quote(query)}%22"
50
35
  url += f"&dataset_id={self.dataset_id}"
51
36
  url += "&limit={page_size}&offset={offset}&select=hostname&orderby=hostname"
52
- agen = self.api_page_iter(url, page_size=self.page_size)
53
- try:
54
- async for response in agen:
55
- subdomains = self.parse_results(response)
56
- self.verbose(f'Got {len(subdomains):,} subdomains for "{query}"')
57
- if not subdomains:
58
- break
59
- yield subdomains
60
- finally:
61
- agen.aclose()
37
+ return url
62
38
 
63
- def parse_results(self, j):
39
+ def parse_results(self, j, query):
64
40
  results = j.get("results", [])
65
41
  subdomains = set()
66
42
  for item in results:
@@ -15,6 +15,10 @@ class virustotal(subdomain_enum_apikey):
15
15
  options_desc = {"api_key": "VirusTotal API Key"}
16
16
 
17
17
  base_url = "https://www.virustotal.com/api/v3"
18
+ api_page_iter_kwargs = {"json": False, "next_key": lambda r: r.json().get("links", {}).get("next", "")}
19
+
20
+ def make_url(self, query):
21
+ return f"{self.base_url}/domains/{self.helpers.quote(query)}/subdomains"
18
22
 
19
23
  def prepare_api_request(self, url, kwargs):
20
24
  kwargs["headers"]["x-apikey"] = self.api_key
@@ -28,17 +32,3 @@ class virustotal(subdomain_enum_apikey):
28
32
  if match.endswith(query):
29
33
  results.add(match)
30
34
  return results
31
-
32
- async def query(self, query):
33
- results = set()
34
- url = f"{self.base_url}/domains/{self.helpers.quote(query)}/subdomains"
35
- agen = self.api_page_iter(url, json=False, next_key=lambda r: r.json().get("links", {}).get("next", ""))
36
- try:
37
- async for response in agen:
38
- r = self.parse_results(response, query)
39
- if not r:
40
- break
41
- results.update(r)
42
- finally:
43
- agen.aclose()
44
- return results
bbot/scanner/scanner.py CHANGED
@@ -130,20 +130,22 @@ class Scanner:
130
130
  else:
131
131
  self.id = f"SCAN:{sha1(rand_string(20)).hexdigest()}"
132
132
 
133
- preset = kwargs.pop("preset", None)
133
+ custom_preset = kwargs.pop("preset", None)
134
134
  kwargs["_log"] = True
135
135
 
136
136
  from .preset import Preset
137
137
 
138
- if preset is None:
139
- preset = Preset(*targets, **kwargs)
140
- else:
141
- if not isinstance(preset, Preset):
142
- raise ValidationError(f'Preset must be of type Preset, not "{type(preset).__name__}"')
143
- self.preset = preset.bake(self)
138
+ base_preset = Preset(*targets, **kwargs)
139
+
140
+ if custom_preset is not None:
141
+ if not isinstance(custom_preset, Preset):
142
+ raise ValidationError(f'Preset must be of type Preset, not "{type(custom_preset).__name__}"')
143
+ base_preset.merge(custom_preset)
144
+
145
+ self.preset = base_preset.bake(self)
144
146
 
145
147
  # scan name
146
- if preset.scan_name is None:
148
+ if self.preset.scan_name is None:
147
149
  tries = 0
148
150
  while 1:
149
151
  if tries > 5:
@@ -158,7 +160,7 @@ class Scanner:
158
160
  break
159
161
  tries += 1
160
162
  else:
161
- scan_name = str(preset.scan_name)
163
+ scan_name = str(self.preset.scan_name)
162
164
  self.name = scan_name
163
165
 
164
166
  # make sure the preset has a description
@@ -166,8 +168,8 @@ class Scanner:
166
168
  self.preset.description = self.name
167
169
 
168
170
  # scan output dir
169
- if preset.output_dir is not None:
170
- self.home = Path(preset.output_dir).resolve() / self.name
171
+ if self.preset.output_dir is not None:
172
+ self.home = Path(self.preset.output_dir).resolve() / self.name
171
173
  else:
172
174
  self.home = self.preset.bbot_home / "scans" / self.name
173
175
 
@@ -14,10 +14,19 @@ async def test_events(events, helpers):
14
14
  await scan._prep()
15
15
 
16
16
  assert events.ipv4.type == "IP_ADDRESS"
17
+ assert events.ipv4.netloc == "8.8.8.8"
18
+ assert events.ipv4.port is None
17
19
  assert events.ipv6.type == "IP_ADDRESS"
20
+ assert events.ipv6.netloc == "[2001:4860:4860::8888]"
21
+ assert events.ipv6.port is None
22
+ assert events.ipv6_open_port.netloc == "[2001:4860:4860::8888]:443"
18
23
  assert events.netv4.type == "IP_RANGE"
24
+ assert events.netv4.netloc is None
25
+ assert "netloc" not in events.netv4.json()
19
26
  assert events.netv6.type == "IP_RANGE"
20
27
  assert events.domain.type == "DNS_NAME"
28
+ assert events.domain.netloc == "publicapis.org"
29
+ assert events.domain.port is None
21
30
  assert "domain" in events.domain.tags
22
31
  assert events.subdomain.type == "DNS_NAME"
23
32
  assert "subdomain" in events.subdomain.tags
@@ -67,8 +76,14 @@ async def test_events(events, helpers):
67
76
  assert not events.netv6 in events.domain
68
77
  assert events.emoji not in events.domain
69
78
  assert events.domain not in events.emoji
70
- assert "evilcorp.com" == scan.make_event(" eViLcorp.COM.:88", "DNS_NAME", dummy=True)
71
- assert "evilcorp.com" == scan.make_event("evilcorp.com.", "DNS_NAME", dummy=True)
79
+ open_port_event = scan.make_event(" eViLcorp.COM.:88", "DNS_NAME", dummy=True)
80
+ dns_event = scan.make_event("evilcorp.com.", "DNS_NAME", dummy=True)
81
+ for e in (open_port_event, dns_event):
82
+ assert "evilcorp.com" == e
83
+ assert e.netloc == "evilcorp.com"
84
+ assert e.json()["netloc"] == "evilcorp.com"
85
+ assert e.port is None
86
+ assert "port" not in e.json()
72
87
 
73
88
  # url tests
74
89
  assert scan.make_event("http://evilcorp.com", dummy=True) == scan.make_event("http://evilcorp.com/", dummy=True)
@@ -78,8 +93,14 @@ async def test_events(events, helpers):
78
93
  assert "api.publicapis.org:443" in events.url_unverified
79
94
  assert "publicapis.org" not in events.url_unverified
80
95
  assert events.ipv4_url_unverified in events.ipv4
96
+ assert events.ipv4_url_unverified.netloc == "8.8.8.8:443"
97
+ assert events.ipv4_url_unverified.port == 443
98
+ assert events.ipv4_url_unverified.json()["port"] == 443
81
99
  assert events.ipv4_url_unverified in events.netv4
82
100
  assert events.ipv6_url_unverified in events.ipv6
101
+ assert events.ipv6_url_unverified.netloc == "[2001:4860:4860::8888]:443"
102
+ assert events.ipv6_url_unverified.port == 443
103
+ assert events.ipv6_url_unverified.json()["port"] == 443
83
104
  assert events.ipv6_url_unverified in events.netv6
84
105
  assert events.emoji not in events.url_unverified
85
106
  assert events.emoji not in events.ipv6_url_unverified
@@ -193,6 +214,8 @@ async def test_events(events, helpers):
193
214
 
194
215
  org_stub_1 = scan.make_event("STUB1", "ORG_STUB", parent=scan.root_event)
195
216
  org_stub_1.scope_distance == 1
217
+ assert org_stub_1.netloc == None
218
+ assert "netloc" not in org_stub_1.json()
196
219
  org_stub_2 = scan.make_event("STUB2", "ORG_STUB", parent=org_stub_1)
197
220
  org_stub_2.scope_distance == 2
198
221
 
@@ -94,6 +94,15 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
94
94
  ]
95
95
  assert helpers.is_ip("127.0.0.1")
96
96
  assert not helpers.is_ip("127.0.0.0.1")
97
+
98
+ assert not helpers.is_ip_type("127.0.0.1")
99
+ assert helpers.is_ip_type(ipaddress.ip_address("127.0.0.1"))
100
+ assert not helpers.is_ip_type(ipaddress.ip_address("127.0.0.1"), network=True)
101
+ assert helpers.is_ip_type(ipaddress.ip_address("127.0.0.1"), network=False)
102
+ assert helpers.is_ip_type(ipaddress.ip_network("127.0.0.0/8"))
103
+ assert helpers.is_ip_type(ipaddress.ip_network("127.0.0.0/8"), network=True)
104
+ assert not helpers.is_ip_type(ipaddress.ip_network("127.0.0.0/8"), network=False)
105
+
97
106
  assert helpers.is_dns_name("evilcorp.com")
98
107
  assert helpers.is_dns_name("evilcorp")
99
108
  assert not helpers.is_dns_name("evilcorp", include_local=False)
@@ -212,8 +221,12 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
212
221
 
213
222
  ipv4_netloc = helpers.make_netloc("192.168.1.1", 80)
214
223
  assert ipv4_netloc == "192.168.1.1:80"
215
- ipv6_netloc = helpers.make_netloc("dead::beef", "443")
216
- assert ipv6_netloc == "[dead::beef]:443"
224
+ assert helpers.make_netloc("192.168.1.1") == "192.168.1.1"
225
+ assert helpers.make_netloc(ipaddress.ip_address("192.168.1.1"), None) == "192.168.1.1"
226
+ assert helpers.make_netloc("dead::beef", "443") == "[dead::beef]:443"
227
+ assert helpers.make_netloc(ipaddress.ip_address("dead::beef"), 443) == "[dead::beef]:443"
228
+ assert helpers.make_netloc("dead::beef", None) == "[dead::beef]"
229
+ assert helpers.make_netloc(ipaddress.ip_address("dead::beef"), None) == "[dead::beef]"
217
230
 
218
231
  assert helpers.get_file_extension("https://evilcorp.com/evilcorp.com/test/asdf.TXT") == "txt"
219
232
  assert helpers.get_file_extension("/etc/conf/test.tar.gz") == "gz"
@@ -575,7 +575,7 @@ async def test_manager_scope_accuracy(bbot_scanner, bbot_httpserver, bbot_other_
575
575
  },
576
576
  )
577
577
 
578
- assert len(events) == 10
578
+ assert len(events) == 12
579
579
  assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal == False and e.scope_distance == 0])
580
580
  assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"])
581
581
  assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal == False and e.scope_distance == 0])
@@ -589,9 +589,9 @@ async def test_manager_scope_accuracy(bbot_scanner, bbot_httpserver, bbot_other_
589
589
  assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"])
590
590
  assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal == False and e.scope_distance == 0])
591
591
  assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"])
592
- assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"])
592
+ assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"])
593
593
  assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"])
594
- assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"])
594
+ assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"])
595
595
  assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal == False and e.scope_distance == 0])
596
596
  assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"])
597
597
  assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal == False and e.scope_distance == 0])
@@ -603,7 +603,7 @@ async def test_manager_scope_accuracy(bbot_scanner, bbot_httpserver, bbot_other_
603
603
  assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"])
604
604
  assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"])
605
605
 
606
- assert len(all_events) == 29
606
+ assert len(all_events) == 31
607
607
  assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal == False and e.scope_distance == 0])
608
608
  assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal == True and e.scope_distance == 0])
609
609
  assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal == False and e.scope_distance == 0])
@@ -618,8 +618,10 @@ async def test_manager_scope_accuracy(bbot_scanner, bbot_httpserver, bbot_other_
618
618
  assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal == False and e.scope_distance == 0])
619
619
  assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal == True and e.scope_distance == 0])
620
620
  assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal == True and e.scope_distance == 0])
621
+ assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal == False and e.scope_distance == 0])
621
622
  assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal == True and e.scope_distance == 0])
622
623
  assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal == True and e.scope_distance == 0])
624
+ assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal == False and e.scope_distance == 0])
623
625
  assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal == False and e.scope_distance == 0])
624
626
  assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal == False and e.scope_distance == 0])
625
627
  assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal == False and e.scope_distance == 0])
@@ -660,7 +662,7 @@ async def test_manager_scope_accuracy(bbot_scanner, bbot_httpserver, bbot_other_
660
662
  assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal == True and e.scope_distance == 1])
661
663
 
662
664
  for _graph_output_events in (graph_output_events, graph_output_batch_events):
663
- assert len(_graph_output_events) == 10
665
+ assert len(_graph_output_events) == 12
664
666
  assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal == False and e.scope_distance == 0])
665
667
  assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"])
666
668
  assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal == False and e.scope_distance == 0])
@@ -674,9 +676,9 @@ async def test_manager_scope_accuracy(bbot_scanner, bbot_httpserver, bbot_other_
674
676
  assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"])
675
677
  assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33"])
676
678
  assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"])
677
- assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"])
679
+ assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"])
678
680
  assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"])
679
- assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"])
681
+ assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"])
680
682
  assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal == False and e.scope_distance == 0])
681
683
  assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"])
682
684
  assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal == False and e.scope_distance == 0])
@@ -380,15 +380,14 @@ async def test_modules_basic_stats(helpers, events, bbot_scanner, httpx_mock, mo
380
380
  scan.modules["dummy"] = dummy(scan)
381
381
  events = [e async for e in scan.async_start()]
382
382
 
383
- assert len(events) == 10
384
- for e in events:
385
- log.critical(e)
383
+ assert len(events) == 11
386
384
  assert 2 == len([e for e in events if e.type == "SCAN"])
387
385
  assert 4 == len([e for e in events if e.type == "DNS_NAME"])
388
386
  # one from target and one from speculate
389
387
  assert 2 == len([e for e in events if e.type == "DNS_NAME" and e.data == "evilcorp.com"])
390
388
  assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "www.evilcorp.com"])
391
389
  assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "asdf.evilcorp.com"])
390
+ assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "asdf.evilcorp.com:443"])
392
391
  assert 1 == len([e for e in events if e.type == "ORG_STUB" and e.data == "evilcorp"])
393
392
  assert 1 == len([e for e in events if e.type == "FINDING"])
394
393
  assert 1 == len([e for e in events if e.type == "URL_UNVERIFIED"])
@@ -397,6 +396,7 @@ async def test_modules_basic_stats(helpers, events, bbot_scanner, httpx_mock, mo
397
396
  "SCAN": 1,
398
397
  "DNS_NAME": 4,
399
398
  "URL": 1,
399
+ "OPEN_TCP_PORT": 1,
400
400
  "ORG_STUB": 1,
401
401
  "URL_UNVERIFIED": 1,
402
402
  "FINDING": 1,
@@ -431,16 +431,17 @@ async def test_modules_basic_stats(helpers, events, bbot_scanner, httpx_mock, mo
431
431
  assert python_stats.consumed == {
432
432
  "DNS_NAME": 4,
433
433
  "FINDING": 1,
434
+ "OPEN_TCP_PORT": 1,
434
435
  "ORG_STUB": 1,
435
436
  "SCAN": 1,
436
437
  "URL": 1,
437
438
  "URL_UNVERIFIED": 1,
438
439
  }
439
- assert python_stats.consumed_total == 9
440
+ assert python_stats.consumed_total == 10
440
441
 
441
442
  speculate_stats = scan.stats.module_stats["speculate"]
442
- assert speculate_stats.produced == {"DNS_NAME": 1, "URL_UNVERIFIED": 1, "ORG_STUB": 1}
443
- assert speculate_stats.produced_total == 3
443
+ assert speculate_stats.produced == {"DNS_NAME": 1, "URL_UNVERIFIED": 1, "ORG_STUB": 1, "OPEN_TCP_PORT": 1}
444
+ assert speculate_stats.produced_total == 4
444
445
  assert speculate_stats.consumed == {"URL": 1, "DNS_NAME": 3, "URL_UNVERIFIED": 1, "IP_ADDRESS": 3}
445
446
  assert speculate_stats.consumed_total == 8
446
447
 
@@ -169,6 +169,11 @@ exclude_flags:
169
169
 
170
170
  def test_preset_scope():
171
171
 
172
+ # test target merging
173
+ scan = Scanner("1.2.3.4", preset=Preset.from_dict({"target": ["evilcorp.com"]}))
174
+ assert set([str(h) for h in scan.preset.target.seeds.hosts]) == {"1.2.3.4", "evilcorp.com"}
175
+ assert set([e.data for e in scan.target]) == {"1.2.3.4", "evilcorp.com"}
176
+
172
177
  blank_preset = Preset()
173
178
  blank_preset = blank_preset.bake()
174
179
  assert not blank_preset.target
@@ -9,13 +9,32 @@ class TestShodan_DNS(ModuleTestBase):
9
9
  url="https://api.shodan.io/api-info?key=asdf",
10
10
  )
11
11
  module_test.httpx_mock.add_response(
12
- url="https://api.shodan.io/dns/domain/blacklanternsecurity.com?key=asdf",
12
+ url="https://api.shodan.io/dns/domain/blacklanternsecurity.com?key=asdf&page=1",
13
13
  json={
14
14
  "subdomains": [
15
15
  "asdf",
16
16
  ],
17
17
  },
18
18
  )
19
+ module_test.httpx_mock.add_response(
20
+ url="https://api.shodan.io/dns/domain/blacklanternsecurity.com?key=asdf&page=2",
21
+ json={
22
+ "subdomains": [
23
+ "www",
24
+ ],
25
+ },
26
+ )
27
+ await module_test.mock_dns(
28
+ {
29
+ "blacklanternsecurity.com": {
30
+ "A": ["127.0.0.11"],
31
+ },
32
+ "www.blacklanternsecurity.com": {"A": ["127.0.0.22"]},
33
+ "asdf.blacklanternsecurity.com": {"A": ["127.0.0.33"]},
34
+ }
35
+ )
19
36
 
20
37
  def check(self, module_test, events):
38
+ assert len([e for e in events if e.type == "DNS_NAME"]) == 3, "Failed to detect both subdomains"
21
39
  assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain"
40
+ assert any(e.data == "www.blacklanternsecurity.com" for e in events), "Failed to detect subdomain"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bbot
3
- Version: 2.1.0.5004rc0
3
+ Version: 2.1.0.5021rc0
4
4
  Summary: OSINT automation for hackers.
5
5
  Home-page: https://github.com/blacklanternsecurity/bbot
6
6
  License: GPL-3.0
@@ -1,4 +1,4 @@
1
- bbot/__init__.py,sha256=2MX0wg8qVd4uv2p2QWKxK-Lgomc0rk8etHVfyVf9jFo,130
1
+ bbot/__init__.py,sha256=YFdfhQ1yOTXBbFgjrv-VG1B22MQAijLczIvIUzcDfdc,130
2
2
  bbot/cli.py,sha256=7S3a4eB-Dl8yodc5WC-927Z30CNlLl9EXimGvIVypJo,10434
3
3
  bbot/core/__init__.py,sha256=l255GJE_DvUnWvrRb0J5lG-iMztJ8zVvoweDOfegGtI,46
4
4
  bbot/core/config/__init__.py,sha256=zYNw2Me6tsEr8hOOkLb4BQ97GB7Kis2k--G81S8vofU,342
@@ -7,7 +7,7 @@ bbot/core/config/logger.py,sha256=C9txmKQtqSFnWU1AapwFS9cZgDBtNZQh4io_13d3AxA,95
7
7
  bbot/core/core.py,sha256=twd7-fiaaxzgcWTPwT1zbSWfAa_gHHfl7gAFvLYvFYg,6358
8
8
  bbot/core/engine.py,sha256=wGopKa2GNs61r16Pr_xtp6Si9AT6I-lE83iWhEgtxwA,29290
9
9
  bbot/core/event/__init__.py,sha256=8ut88ZUg0kbtWkOx2j3XzNr_3kTfgoM-3UdiWHFA_ag,56
10
- bbot/core/event/base.py,sha256=ZAz5jEd7sEX8Bl0EVdCpdOD7jXNjcdlqOJ83GpckCA8,58963
10
+ bbot/core/event/base.py,sha256=MYgwrrIck5bF9GlxQe5jNWnFM-o1zvfVgFDQlb1Jh14,59235
11
11
  bbot/core/event/helpers.py,sha256=PUN4Trq5_wpKVuhmwUQWAr40apgMXhJ9Gz-VfZ0j3lA,1554
12
12
  bbot/core/flags.py,sha256=Ltvm8Bc4D65I55HuU5bzyjO1R3yMDNpVmreGU83ZBXE,1266
13
13
  bbot/core/helpers/__init__.py,sha256=0UNwcZjNsX41hbHdo3yZPuARkYWch-okI68DScexve4,86
@@ -28,7 +28,7 @@ bbot/core/helpers/dns/mock.py,sha256=Ztkp2aOuwDJ0NTQSlAk2H0s3Stx9wIM22Qm3VtqWMKM
28
28
  bbot/core/helpers/files.py,sha256=GqrwNGJljUvGSzaOW5-Y357hkt7j88dOYbzQxJGsdTc,5787
29
29
  bbot/core/helpers/helper.py,sha256=3O96peNBvSkaJosft8w9-nKjCscEdykTayGcUlHRqLw,8394
30
30
  bbot/core/helpers/interactsh.py,sha256=Q9IHUzH-T7e1s4YTHevHe-VJj1Mokv0EHY16UZJdl8M,12627
31
- bbot/core/helpers/misc.py,sha256=jhQsCAESXin5eBOQ5n8Uq5UhB4lcBjuBv3SEEaCaOEQ,86526
31
+ bbot/core/helpers/misc.py,sha256=rvfZmm8UHCChmbMorjPMybaCZTkERrKZhxvY9S4dVPc,86873
32
32
  bbot/core/helpers/names_generator.py,sha256=Sj_Q-7KQyElEpalzlUadSwaniESqrIVVEle9ycPIiho,10322
33
33
  bbot/core/helpers/ntlm.py,sha256=P2Xj4-GPos2iAzw4dfk0FJp6oGyycGhu2x6sLDVjYjs,2573
34
34
  bbot/core/helpers/process.py,sha256=6D9_LYZrhQ0Jb7Rn58rWMafmAZn7rVVA2LqMKwpR_xg,2271
@@ -58,7 +58,7 @@ bbot/modules/baddns.py,sha256=FFGpJ0AdcpYBh_i8VMYOUj6C_PhzkFls263DoVmUXGY,6376
58
58
  bbot/modules/baddns_direct.py,sha256=_Z_snPDU5VqF3jb2CAoX5Sb94GnhYVP22JIK5TdpF_Y,3820
59
59
  bbot/modules/baddns_zone.py,sha256=bTpYzQYLt4ZJo_Jan5K4NsYL7O1PMVQvJHmYPy6QyvY,1035
60
60
  bbot/modules/badsecrets.py,sha256=WMeIhjafD63sXShYGtbAk2kw12PgxMIZh8EMbYg7x20,5108
61
- bbot/modules/base.py,sha256=HiffBnsNcCjKIgp_IHg82NAsXDXlnvoPs2wvx6HBZ6k,70893
61
+ bbot/modules/base.py,sha256=-nPgoPjMwcveZ81fzb4TwhbtBFqNYorj-zD3TG91ZPg,71115
62
62
  bbot/modules/bevigil.py,sha256=EFA4N_aJDF20KjrzbzdkHaTL1GfOF6ohBMlNIEJne6s,2850
63
63
  bbot/modules/binaryedge.py,sha256=W6VMbV7-tVAduUNbcmS6uLLJixb3sDJmqC9m4IGB6Yg,1391
64
64
  bbot/modules/bucket_amazon.py,sha256=mwjYeEAcdfOpjbOa1sD8U9KBMMVY_c8FoHjSGR9GQbg,730
@@ -96,7 +96,7 @@ bbot/modules/ffuf_shortnames.py,sha256=9Kh0kJsw7XXpXmCkiB5eAhG4h9rSo8Y-mB3p0EDa_
96
96
  bbot/modules/filedownload.py,sha256=1prC84wAQO-W1HstitKPQ0-eYEApjzFn3RHFa9oaqLc,8185
97
97
  bbot/modules/fingerprintx.py,sha256=rdlR9d64AntAhbS_eJzh8bZCeLPTJPSKdkdKdhH_qAo,3269
98
98
  bbot/modules/fullhunt.py,sha256=R70VpNZezUOeCOuYiYaG3oJCIOjOjB6lMPaVJ-xPVr0,1305
99
- bbot/modules/generic_ssrf.py,sha256=ZkaZuQE_sKlHH0uBUtJ45UKcGU91tdq8-n3ypneYdqA,7980
99
+ bbot/modules/generic_ssrf.py,sha256=FZ7XZ2RbBk5PVwa7wHasSkEsatUFWvCH70ZvPbg-EQA,7946
100
100
  bbot/modules/git.py,sha256=CMDarsmBemZEzZSeQTzB70XD8IRdwdG39zXpwDdgZbw,1383
101
101
  bbot/modules/git_clone.py,sha256=XFZXx0k97EMY3E5PZzdNvqQzZddOfRMaVp5ol2gk11s,2468
102
102
  bbot/modules/github_codesearch.py,sha256=VbzSsnJKL1SWSl6rB88qWl26bAgszM7Gbo4HCOl6XUU,3540
@@ -115,9 +115,9 @@ bbot/modules/internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
115
115
  bbot/modules/internal/aggregate.py,sha256=csWYIt2fUp9K_CRxP3bndUMIjpNIh8rmBubp5Fr1-nc,395
116
116
  bbot/modules/internal/base.py,sha256=BXO4Hc7XKaAOaLzolF3krJX1KibPxtek2GTQUgnCHk0,387
117
117
  bbot/modules/internal/cloudcheck.py,sha256=kkD5DC5Y7EPCiVTdEspZktkflArU3unx--9ciBikxHo,4099
118
- bbot/modules/internal/dnsresolve.py,sha256=IYIbtwvHzsVHsnBkgAmRUNMc3nnG5DuH4tBnq4Ja0FU,14923
119
- bbot/modules/internal/excavate.py,sha256=eQNorIZz0NHnsRYPt1MOR2Oj4Uc6---q4OSfr3ErNC4,51118
120
- bbot/modules/internal/speculate.py,sha256=diAI1_RGdcoKCBTiwsplReHNxL7S85OmBc8hsvr2yuA,9832
118
+ bbot/modules/internal/dnsresolve.py,sha256=rmXBb6r8MNYrHlnTbES1ok5M9q3JD3Oj6AOx6d0Bawc,14558
119
+ bbot/modules/internal/excavate.py,sha256=1kPiaUlpJVT_xgPgmzqhpf04uanIe9ZayQsWANbzhd4,51238
120
+ bbot/modules/internal/speculate.py,sha256=wP75lpdnxhoGiARmSdIlvPyYHQKx1Tu6oCu7_sKV9Qs,9850
121
121
  bbot/modules/internetdb.py,sha256=Edg0Z84dH8dPTZMd7RlzvYBYNq8JHs_ns_ldnFxwRKo,5415
122
122
  bbot/modules/ip2location.py,sha256=yGivX9fzvwvLpnqmYCP2a8SPjTarzrZxfRluog-nkME,2628
123
123
  bbot/modules/ipneighbor.py,sha256=Gr-HGtyZRDp_fPjpw-Mq1al7ocFdiZbKsAoAit-EUlA,1591
@@ -162,7 +162,7 @@ bbot/modules/robots.py,sha256=G2_IvLcI24iMXJxii44H1z6m5KWe2NMIDtVMbQGaXDE,2172
162
162
  bbot/modules/secretsdb.py,sha256=MA6IKo5rOvC0Dzt-F4QVrSwLkcPRwWLd9FpzqYkc8u8,3082
163
163
  bbot/modules/securitytrails.py,sha256=j2ZcY_qO48mQquWwS3FOaHgZiomr2ETMGv28y5qtRZM,1088
164
164
  bbot/modules/securitytxt.py,sha256=-GuIelHW04256VlcgfyV4ylfo7oSbAwToxtV2Cfo2p0,4558
165
- bbot/modules/shodan_dns.py,sha256=G0Wt8Uure-oY63n0ctRtQNzSGD6YFo3UnBz8Fjk4jJY,876
165
+ bbot/modules/shodan_dns.py,sha256=PJaeqGlTfhQfKgc_3fDmC4mLWsOb4BnRUpVD_h3Y8cU,836
166
166
  bbot/modules/sitedossier.py,sha256=0GOGMt0x3wro2FvP4ngNa2lcTmcjjq5x1SM8l5HG8Cs,2283
167
167
  bbot/modules/skymem.py,sha256=NApG68Eh22jMcV1H590SXvQIlLJY4JOfGUeNaOJaMKs,1928
168
168
  bbot/modules/smuggler.py,sha256=v8NCRgzd7wpEFZJUTAArG04bN8nNTGiHxYpGBapzi14,1580
@@ -175,15 +175,15 @@ bbot/modules/templates/bucket.py,sha256=x-c_iAeMILux6wRm0xkUUJkc2P69hYWS6DxqD7g5
175
175
  bbot/modules/templates/github.py,sha256=ENnDWpzzmZBsTisDx6Cg9V_NwJKyVyPIOpGAPktigdI,1455
176
176
  bbot/modules/templates/postman.py,sha256=oxwVusW2EdNotVX7xnnxCTnWtj3xNPbfs8aff9s4phs,614
177
177
  bbot/modules/templates/shodan.py,sha256=BfI0mNPbqkykGmjMtARhmCGKmk1uq7yTlZoPgzzJ040,1175
178
- bbot/modules/templates/subdomain_enum.py,sha256=W6UC3r2qkEryJAiwTz523G2STql3f8SDKGmlF79XQM0,6805
178
+ bbot/modules/templates/subdomain_enum.py,sha256=lT5MZF66OuzsyFFrj20wKlsZflzL9MOkPjDIbN3o65o,8375
179
179
  bbot/modules/templates/webhook.py,sha256=MYhKWrNYrsfM0a4PR6yVotudLyyCwgmy2eI-l9LvpBs,3706
180
- bbot/modules/trickest.py,sha256=dPUeUsOy0saUcFlpOyPXDh3ESKL2LIqH_oQkuAR4ToE,2657
180
+ bbot/modules/trickest.py,sha256=HfAzjnawxXd9ypi3gumDHqImE5-C7uwNugo8d_b9HT0,1544
181
181
  bbot/modules/trufflehog.py,sha256=KMFYbjKEyoNaJDoID0SoDvbCRPaDwalMD6H2lQaI1QE,8555
182
182
  bbot/modules/unstructured.py,sha256=si3_Y__A36QOBdkIUocVXCHrmUqM0E-JSnoOeRpELYE,5311
183
183
  bbot/modules/url_manipulation.py,sha256=BI-OhlzNzP5xvwzHphL4qdehc4NiEYnL2BNK-JoEm90,4322
184
184
  bbot/modules/urlscan.py,sha256=ajhiX2sj-zZDlKU1q5rE8JTzxioj1mDLqZ9PRSQCpAw,3741
185
185
  bbot/modules/viewdns.py,sha256=f0vwoLpua2Ovw1gcrjoafUdaAP9fi4bHgTUiDOe8iWg,2596
186
- bbot/modules/virustotal.py,sha256=hQZe1jgcC65fNHrYV98EMFQfi-j7qVyT4NAlfxsiEgc,1505
186
+ bbot/modules/virustotal.py,sha256=GsGaVF05IMgSNOQtUx1B8UXL5JA1Bt8M6ZDWJiiEQ1k,1213
187
187
  bbot/modules/wafw00f.py,sha256=I-jEnHWxO4Ga72ukdeBlTGJB9xeucCT3lpDhhFaVyAk,2536
188
188
  bbot/modules/wappalyzer.py,sha256=LL5QeY5DeG7LdaFzZZU-LXaVlJ-sHzOwQLgFtxW3TNg,2176
189
189
  bbot/modules/wayback.py,sha256=9cxd_HfHgLp4AChzA8C0Zjd6DIJ7c3NsJ02W2oLIXuU,3257
@@ -213,7 +213,7 @@ bbot/scanner/preset/conditions.py,sha256=hFL9cSIWGEsv2TfM5UGurf0c91cyaM8egb5IngB
213
213
  bbot/scanner/preset/environ.py,sha256=-wbFk1YHpU8IJLKVw23Q3btQTICeX0iulURo7D673L0,4732
214
214
  bbot/scanner/preset/path.py,sha256=p9tZC7XcgZv2jXpbEJAg1lU2b4ZLX5COFnCxEUOXz2g,2234
215
215
  bbot/scanner/preset/preset.py,sha256=nhAPjV-9P-udAs_CK5oOVuCeQP_c-a6Nem0SaNF98Ss,40216
216
- bbot/scanner/scanner.py,sha256=UyTpW1qTvegugUd2MWwtAE9CsAOs7bBmM8kMSqY7uCo,53583
216
+ bbot/scanner/scanner.py,sha256=62DKCjgV1uLxNAwpxjvE5h1uzQCxG-nzBxp1PBCSVKc,53674
217
217
  bbot/scanner/stats.py,sha256=re93sArKXZSiD0Owgqk2J3Kdvfm3RL4Y9Qy_VOcaVk8,3623
218
218
  bbot/scanner/target.py,sha256=X25gpgRv5HmqQjGADiSe6b8744yOkRhAGAvKKYbXnSI,19886
219
219
  bbot/scripts/docs.py,sha256=kg2CzovmUVGJx9hBZjAjUdE1hXeIwC7Ry3CyrnE8GL8,10782
@@ -235,13 +235,13 @@ bbot/test/test_step_1/test_depsinstaller.py,sha256=zr9f-wJDotD1ZvKXGEuDRWzFYMAYB
235
235
  bbot/test/test_step_1/test_dns.py,sha256=YZtSbja-Z76KC9MWBieRExolVWHm0WqssL0WHUpUiC8,30932
236
236
  bbot/test/test_step_1/test_docs.py,sha256=YWVGNRfzcrvDmFekX0Cq9gutQplsqvhKTpZ0XK4tWvo,82
237
237
  bbot/test/test_step_1/test_engine.py,sha256=Bfid3-D9ziN93w4vym97tFEn_l2Iof08wjITTv_lAZw,4269
238
- bbot/test/test_step_1/test_events.py,sha256=-nBbVfJdsEvx_W0X4aO9RpXGBZ61y1QwTjreDq494s8,43765
238
+ bbot/test/test_step_1/test_events.py,sha256=0SV3BEagDCsoRw6yui_DvkQ0Vr3VVjwHyRhtmCDGdPQ,44847
239
239
  bbot/test/test_step_1/test_files.py,sha256=5Q_3jPpMXULxDHsanSDUaj8zF8bXzKdiJZHOmoYpLhQ,699
240
- bbot/test/test_step_1/test_helpers.py,sha256=kRd64C_LD6VhBM1UJrWlkX1rGLFW0QtAj8mPX0dgbq4,37787
240
+ bbot/test/test_step_1/test_helpers.py,sha256=oY2hWhgL-TCB67ve1bAyIwZO3wNRWpx4SjCHNUxHep8,38676
241
241
  bbot/test/test_step_1/test_manager_deduplication.py,sha256=hZQpDXzg6zvzxFolVOcJuY-ME8NXjZUsqS70BRNXp8A,15594
242
- bbot/test/test_step_1/test_manager_scope_accuracy.py,sha256=5CptaGVplTLsGx7THjrJva99M9rumd7JCUFjTAXYUVE,79454
243
- bbot/test/test_step_1/test_modules_basic.py,sha256=JlO1waj6JArpazCUIYaNzOIv1qnKs-ArrfXw1D2B_tA,20155
244
- bbot/test/test_step_1/test_presets.py,sha256=SY-A3q3ubwFPJ0dSEgo9DHud-VpNrJa-PS-BGw2P_j8,36870
242
+ bbot/test/test_step_1/test_manager_scope_accuracy.py,sha256=_4O5bW9PA2DIeguvqzb4CMm0i1joqqBBppw7qElL2a0,79767
243
+ bbot/test/test_step_1/test_modules_basic.py,sha256=h4eCe-UhniwXZGhTEa6tH-RGeBF8tyjpSHAPsSu-ssw,20295
244
+ bbot/test/test_step_1/test_presets.py,sha256=I9-T7QOtw5ZbzwJcOnTC-_n2toFlOkhV-E42utaSSf4,37155
245
245
  bbot/test/test_step_1/test_python_api.py,sha256=BYIVREUy7rd7tKfUsnIX-w_eqQDTEo5UplMZeGMb4bs,5317
246
246
  bbot/test/test_step_1/test_regexes.py,sha256=btlDgwM5crSkXFZNydLYn8lCDmyLW_8oX_6Aos5xAHk,14376
247
247
  bbot/test/test_step_1/test_scan.py,sha256=yLQAZ5tvIwTULBGgUmXVg8KwMmujal7kB2p-S2_ORzA,5461
@@ -348,7 +348,7 @@ bbot/test/test_step_2/module_tests/test_module_robots.py,sha256=8rRw4GpGE6tN_W3o
348
348
  bbot/test/test_step_2/module_tests/test_module_secretsdb.py,sha256=EmqWGnqAQHGEZxbmJJXHwIgz5SQi4R3Fq982k6sYkZM,537
349
349
  bbot/test/test_step_2/module_tests/test_module_securitytrails.py,sha256=NB8_PhWN1-2s8wporRjI6rrQeQW4inoz4Z_mBhhycXo,758
350
350
  bbot/test/test_step_2/module_tests/test_module_securitytxt.py,sha256=i9Emp1utut1LPIe502Jb3XzN4GiVBeo4ATLFR9w4rbY,2382
351
- bbot/test/test_step_2/module_tests/test_module_shodan_dns.py,sha256=DQvs4e3_vtAfkzTCTHfFMh8UZHag6bUs_m6nbWL9rvM,713
351
+ bbot/test/test_step_2/module_tests/test_module_shodan_dns.py,sha256=9DpFizZguP2aFCKI1HgXzxy3sB_afA03pzIx0BDfgqg,1515
352
352
  bbot/test/test_step_2/module_tests/test_module_sitedossier.py,sha256=YAaTzCL-lOYFu-42zk4dsV33V3Da3Md6rcAuBy9jgeY,6584
353
353
  bbot/test/test_step_2/module_tests/test_module_skymem.py,sha256=VaRhEmrZ0auKmxExeuYmzryXpZ0h78AqSVozkqJ5dXo,2321
354
354
  bbot/test/test_step_2/module_tests/test_module_slack.py,sha256=oJvUzSowPAhpbMFnzl-iS3XvLQBxCaO_vofhu_bgR4w,317
@@ -393,8 +393,8 @@ bbot/wordlists/raft-small-extensions-lowercase_CLEANED.txt,sha256=ruUQwVfia1_m2u
393
393
  bbot/wordlists/top_open_ports_nmap.txt,sha256=LmdFYkfapSxn1pVuQC2LkOIY2hMLgG-Xts7DVtYzweM,42727
394
394
  bbot/wordlists/valid_url_schemes.txt,sha256=VciB-ww0y-O8Ii1wpTR6rJzGDiC2r-dhVsIJApS1ZYU,3309
395
395
  bbot/wordlists/wordninja_dns.txt.gz,sha256=DYHvvfW0TvzrVwyprqODAk4tGOxv5ezNmCPSdPuDUnQ,570241
396
- bbot-2.1.0.5004rc0.dist-info/LICENSE,sha256=GzeCzK17hhQQDNow0_r0L8OfLpeTKQjFQwBQU7ZUymg,32473
397
- bbot-2.1.0.5004rc0.dist-info/METADATA,sha256=zye_cTeYT3jp0QSL3ThNRjBVFQVEHpADQQgJqjqWiow,16930
398
- bbot-2.1.0.5004rc0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
399
- bbot-2.1.0.5004rc0.dist-info/entry_points.txt,sha256=cWjvcU_lLrzzJgjcjF7yeGuRA_eDS8pQ-kmPUAyOBfo,38
400
- bbot-2.1.0.5004rc0.dist-info/RECORD,,
396
+ bbot-2.1.0.5021rc0.dist-info/LICENSE,sha256=GzeCzK17hhQQDNow0_r0L8OfLpeTKQjFQwBQU7ZUymg,32473
397
+ bbot-2.1.0.5021rc0.dist-info/METADATA,sha256=nNxiHMIeFanIaheXaCaAImw6khiqaG55DiVtRbmFUno,16930
398
+ bbot-2.1.0.5021rc0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
399
+ bbot-2.1.0.5021rc0.dist-info/entry_points.txt,sha256=cWjvcU_lLrzzJgjcjF7yeGuRA_eDS8pQ-kmPUAyOBfo,38
400
+ bbot-2.1.0.5021rc0.dist-info/RECORD,,