bbot 2.4.2.6706rc0__py3-none-any.whl → 2.5.0.6715rc0__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.

Potentially problematic release.


This version of bbot might be problematic. Click here for more details.

bbot/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # version placeholder (replaced by poetry-dynamic-versioning)
2
- __version__ = "v2.4.2.6706rc"
2
+ __version__ = "v2.5.0.6715rc"
3
3
 
4
4
  from .scanner import Scanner, Preset
5
5
 
@@ -11,7 +11,7 @@ class lightfuzz(BaseModule):
11
11
 
12
12
  options = {
13
13
  "force_common_headers": False,
14
- "enabled_submodules": ["sqli", "cmdi", "xss", "path", "ssti", "crypto", "serial", "nosqli"],
14
+ "enabled_submodules": ["sqli", "cmdi", "xss", "path", "ssti", "crypto", "serial"],
15
15
  "disable_post": False,
16
16
  }
17
17
  options_desc = {
@@ -153,10 +153,20 @@ class serial(BaseLightfuzz):
153
153
  error in response.text for error in general_errors
154
154
  ) # ensure the 200 is not actually an error
155
155
  ):
156
+
157
+ def get_title(text):
158
+ soup = self.lightfuzz.helpers.beautifulsoup(text, "html.parser")
159
+ if soup and soup.title and soup.title.string:
160
+ return f"'{self.lightfuzz.helpers.truncate_string(soup.title.string, 50)}'"
161
+ return ""
162
+
163
+ baseline_title = get_title(payload_baseline.baseline.text)
164
+ probe_title = get_title(response.text)
165
+
156
166
  self.results.append(
157
167
  {
158
168
  "type": "FINDING",
159
- "description": f"POSSIBLE Unsafe Deserialization. {self.metadata()} Technique: [Error Resolution] Serialization Payload: [{type}]",
169
+ "description": f"POSSIBLE Unsafe Deserialization. {self.metadata()} Technique: [Error Resolution (Baseline: [{payload_baseline.baseline.status_code}] {baseline_title} -> Probe: [{status_code}] {probe_title})] Serialization Payload: [{type}]",
160
170
  }
161
171
  )
162
172
  # if the first case doesn't match, we check for a telltale error string like "java.io.optionaldataexception" in the response.
@@ -111,6 +111,7 @@ class sqli(BaseLightfuzz):
111
111
  single_quote[3].status_code != 429
112
112
  and double_single_quote[3].status_code != 429
113
113
  and http_compare.baseline.status_code != 429
114
+ and http_compare.baseline.status_code != 403 # Ensure the baseline status code is not 403
114
115
  ): # prevent false positives from rate limiting
115
116
  # if the code changed in the single quote probe, and the code is NOT the same between that and the double single quote probe, SQL injection is indicated
116
117
  if "code" in single_quote[1] and (
@@ -142,14 +142,14 @@ class xss(BaseLightfuzz):
142
142
  break
143
143
 
144
144
  if in_tag_attribute:
145
- in_tag_attribute_probe = f'{random_string}"'
146
- in_tag_attribute_match = f'{random_string}"'
145
+ in_tag_attribute_probe = f'{random_string}"z'
146
+ in_tag_attribute_match = f'{random_string}"z'
147
147
  await self.check_probe(
148
148
  cookies, in_tag_attribute_probe, in_tag_attribute_match, "Tag Attribute"
149
149
  ) # After reflection in the HTTP response, did the quote survive without url-encoding or other sanitization/escaping?
150
150
 
151
- in_tag_attribute_probe = f'{random_string}"'
152
- in_tag_attribute_match = f'"{random_string}""'
151
+ in_tag_attribute_probe = f'{random_string}"z'
152
+ in_tag_attribute_match = f'"{random_string}""z'
153
153
  await self.check_probe(
154
154
  cookies, in_tag_attribute_probe, in_tag_attribute_match, "Tag Attribute (autoquote)"
155
155
  ) # After reflection in the HTTP response, did the quote survive without url-encoding or other sanitization/escaping (and account for auto-quoting)
@@ -12,5 +12,5 @@ modules:
12
12
  config:
13
13
  modules:
14
14
  lightfuzz:
15
- enabled_submodules: [cmdi,crypto,nosqli,path,serial,sqli,ssti,xss]
15
+ enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss]
16
16
  disable_post: False
@@ -11,4 +11,4 @@ modules:
11
11
  config:
12
12
  modules:
13
13
  lightfuzz:
14
- enabled_submodules: [cmdi,crypto,nosqli,path,serial,sqli,ssti,xss]
14
+ enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss]
@@ -8,6 +8,6 @@ config:
8
8
  modules:
9
9
  lightfuzz:
10
10
  force_common_headers: True # Fuzz common headers like X-Forwarded-For even if they're not observed on the target
11
- enabled_submodules: [cmdi,crypto,nosqli,path,serial,sqli,ssti,xss]
11
+ enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss]
12
12
  excavate:
13
13
  speculate_params: True # speculate potential parameters extracted from JSON/XML web responses
@@ -639,132 +639,6 @@ class Test_Lightfuzz_urlencoding(Test_Lightfuzz_xss_injs):
639
639
  assert xss_finding_emitted, "In Javascript XSS FINDING not emitted"
640
640
 
641
641
 
642
- class Test_Lightfuzz_nosqli_quoteescape(ModuleTestBase):
643
- targets = ["http://127.0.0.1:8888"]
644
- modules_overrides = ["httpx", "lightfuzz", "excavate"]
645
- config_overrides = {
646
- "interactsh_disable": True,
647
- "modules": {
648
- "lightfuzz": {
649
- "enabled_submodules": ["nosqli"],
650
- }
651
- },
652
- }
653
-
654
- def request_handler(self, request):
655
- normal_block = """
656
- <section class="search-filters">
657
- <label>Refine your search:</label>
658
- <a class="filter-category" href="/?category=Pets">Pets</a>
659
- </section>
660
- """
661
-
662
- qs = str(request.query_string.decode())
663
- if "category=" in qs:
664
- value = qs.split("=")[1]
665
- if "&" in value:
666
- value = value.split("&")[0]
667
- if value == "Pets%27":
668
- return Response("JSON ERROR!", status=500)
669
- elif value == "Pets%5C%27":
670
- return Response("No results", status=200)
671
- elif value == "Pets%27%20%26%26%200%20%26%26%20%27x":
672
- return Response("No results", status=200)
673
- elif value == "Pets%27%20%26%26%201%20%26%26%20%27x":
674
- return Response('{"category":"Pets","entries":["dog","cat","bird"]}', status=200)
675
- else:
676
- return Response("No results", status=200)
677
- return Response(normal_block, status=200)
678
-
679
- async def setup_after_prep(self, module_test):
680
- module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA"
681
- expect_args = re.compile("/")
682
- module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler)
683
-
684
- def check(self, module_test, events):
685
- nosqli_finding_emitted = False
686
- finding_count = 0
687
- for e in events:
688
- if e.type == "FINDING":
689
- finding_count += 1
690
- if (
691
- "Possible NoSQL Injection. Parameter: [category] Parameter Type: [GETPARAM] Original Value: [Pets] Detection Method: [Quote/Escaped Quote + Conditional Affect]"
692
- in e.data["description"]
693
- ):
694
- nosqli_finding_emitted = True
695
- assert nosqli_finding_emitted, "NoSQLi FINDING not emitted"
696
- assert finding_count == 1, "Unexpected FINDING events reported"
697
-
698
-
699
- class Test_Lightfuzz_nosqli_negation(Test_Lightfuzz_nosqli_quoteescape):
700
- def request_handler(self, request):
701
- form_block = """
702
- <form method="POST" action="">
703
- <label for="username">Username:</label>
704
- <input type="text" id="username" name="username" required>
705
- <br>
706
- <label for="password">Password:</label>
707
- <input type="password" id="password" name="password" required>
708
- <br>
709
- <button type="submit">Login</button>
710
- </form>
711
- """
712
- if request.method == "GET":
713
- return Response(form_block, status=200)
714
-
715
- if "username[$ne]" in request.form.keys() and "password[$ne]" in request.form.keys():
716
- return Response("Welcome, testuser1!", status=200)
717
- if "username[$eq]" in request.form.keys() and "password[$eq]" in request.form.keys():
718
- return Response("Invalid Username or Password!", status=200)
719
- else:
720
- return Response("Invalid Username or Password!", status=200)
721
-
722
- def check(self, module_test, events):
723
- nosqli_finding_emitted = False
724
- finding_count = 0
725
- for e in events:
726
- if e.type == "FINDING":
727
- finding_count += 1
728
- if (
729
- "Possible NoSQL Injection. Parameter: [password] Parameter Type: [POSTPARAM] Detection Method: [Parameter Name Operator Injection - Negation ([$ne])] Differences: [body]"
730
- in e.data["description"]
731
- ):
732
- nosqli_finding_emitted = True
733
- assert nosqli_finding_emitted, "NoSQLi FINDING not emitted"
734
- assert finding_count == 2, "Unexpected FINDING events reported"
735
-
736
-
737
- class Test_Lightfuzz_nosqli_negation_falsepositive(Test_Lightfuzz_nosqli_quoteescape):
738
- def request_handler(self, request):
739
- form_block = """
740
- <form method="POST" action="">
741
- <label for="username">Username:</label>
742
- <input type="text" id="username" name="username" required>
743
- <br>
744
- <label for="password">Password:</label>
745
- <input type="password" id="password" name="password" required>
746
- <br>
747
- <button type="submit">Login</button>
748
- </form>
749
- """
750
- if request.method == "GET":
751
- return Response(form_block, status=200)
752
-
753
- if "username[$ne]" in request.form.keys() and "password[$ne]" in request.form.keys():
754
- return Response("missing username or password", status=500)
755
- if "username[$eq]" in request.form.keys() and "password[$eq]" in request.form.keys():
756
- return Response("missing username or password", status=500)
757
- else:
758
- return Response("Invalid Username or Password!", status=200)
759
-
760
- def check(self, module_test, events):
761
- finding_count = 0
762
- for e in events:
763
- if e.type == "FINDING":
764
- finding_count += 1
765
- assert finding_count == 0, "False positive FINDING emitted"
766
-
767
-
768
642
  # SQLI Single Quote/Two Single Quote (getparam)
769
643
  class Test_Lightfuzz_sqli(ModuleTestBase):
770
644
  targets = ["http://127.0.0.1:8888"]
@@ -1040,8 +914,6 @@ class Test_Lightfuzz_sqli_cookies(Test_Lightfuzz_sqli):
1040
914
  </html>
1041
915
  """
1042
916
 
1043
- print("@@@@@???")
1044
- print(request.cookies)
1045
917
  if request.cookies.get("test") is not None:
1046
918
  header_value = request.cookies.get("test")
1047
919
 
@@ -1226,7 +1098,7 @@ class Test_Lightfuzz_serial_errorresolution(ModuleTestBase):
1226
1098
  if e.type == "FINDING":
1227
1099
  if (
1228
1100
  e.data["description"]
1229
- == "POSSIBLE Unsafe Deserialization. Parameter: [TextBox1] Parameter Type: [POSTPARAM] Technique: [Error Resolution] Serialization Payload: [dotnet_base64]"
1101
+ == "POSSIBLE Unsafe Deserialization. Parameter: [TextBox1] Parameter Type: [POSTPARAM] Technique: [Error Resolution (Baseline: [500] -> Probe: [200] )] Serialization Payload: [dotnet_base64]"
1230
1102
  ):
1231
1103
  lightfuzz_serial_detect_errorresolution = True
1232
1104
 
@@ -1326,7 +1198,7 @@ class Test_Lightfuzz_serial_errorresolution_existingvalue_valid(Test_Lightfuzz_s
1326
1198
  excavate_detect_serialization_value = True
1327
1199
  if (
1328
1200
  e.data["description"]
1329
- == "POSSIBLE Unsafe Deserialization. Parameter: [TextBox1] Parameter Type: [POSTPARAM] Original Value: [AAEAAAD/////AQAAAAAAAAAGAQAAAAdndXN0YXZvCw==] Technique: [Error Resolution] Serialization Payload: [dotnet_base64]"
1201
+ == "POSSIBLE Unsafe Deserialization. Parameter: [TextBox1] Parameter Type: [POSTPARAM] Original Value: [AAEAAAD/////AQAAAAAAAAAGAQAAAAdndXN0YXZvCw==] Technique: [Error Resolution (Baseline: [500] -> Probe: [200] )] Serialization Payload: [dotnet_base64]"
1330
1202
  ):
1331
1203
  lightfuzz_serial_detect_errorresolution = True
1332
1204
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bbot
3
- Version: 2.4.2.6706rc0
3
+ Version: 2.5.0.6715rc0
4
4
  Summary: OSINT automation for hackers.
5
5
  License: GPL-3.0
6
6
  Keywords: python,cli,automation,osint,threat-intel,intelligence,neo4j,scanner,python-library,hacking,recursion,pentesting,recon,command-line-tool,bugbounty,subdomains,security-tools,subdomain-scanner,osint-framework,attack-surface,subdomain-enumeration,osint-tool
@@ -1,4 +1,4 @@
1
- bbot/__init__.py,sha256=s1OTUHWAHT3aJvwRblp7G38RUxmbxe716-VaBNn5r2k,163
1
+ bbot/__init__.py,sha256=yccQ2-fVLMX5ykoO0zFuYDxnjbewc43wdlTr_8NF3yw,163
2
2
  bbot/cli.py,sha256=1QJbANVw9Q3GFM92H2QRV2ds5756ulm08CDZwzwPpeI,11888
3
3
  bbot/core/__init__.py,sha256=l255GJE_DvUnWvrRb0J5lG-iMztJ8zVvoweDOfegGtI,46
4
4
  bbot/core/config/__init__.py,sha256=zYNw2Me6tsEr8hOOkLb4BQ97GB7Kis2k--G81S8vofU,342
@@ -133,17 +133,16 @@ bbot/modules/ipneighbor.py,sha256=b_0IhorihFLtXJZEz57EGXjXW30gIOEzzVgz2GFvM3A,15
133
133
  bbot/modules/ipstack.py,sha256=j_S8WMNqQuSQgBT7AX4tO70fgbWuRYrpsS3tVsu_hn4,2200
134
134
  bbot/modules/jadx.py,sha256=8ncbK5i3B6i253qJ5tuD3-cPl4S8qqRvnTVINFTjtvQ,3084
135
135
  bbot/modules/leakix.py,sha256=4sKghkId5cX_eVqTSFsqdNzX5JmUemr-U7gs8PfKVVA,1561
136
- bbot/modules/lightfuzz/lightfuzz.py,sha256=ZKk2wLaVUrZzr4pH_1k0xtf8LrxssAyh4Y61dY0zGS4,8921
136
+ bbot/modules/lightfuzz/lightfuzz.py,sha256=REs0wkwpvrL4bZAg8V1Ui3KFyvgWVtDSk8jP_fFcaCQ,8911
137
137
  bbot/modules/lightfuzz/submodules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
138
138
  bbot/modules/lightfuzz/submodules/base.py,sha256=PvMEoEqrgAmp63JufaPe9GhOn7ay3oBvvZCuFIzuwaI,12619
139
139
  bbot/modules/lightfuzz/submodules/cmdi.py,sha256=-9pL7Yh7VVCObxuS6Qu2cKEJBstfk0oXIkMyntg8xDk,5043
140
140
  bbot/modules/lightfuzz/submodules/crypto.py,sha256=mLWsMbcox9oruNjfdOaLmT7ePMH15K8JN9K5AIB8f8o,22560
141
- bbot/modules/lightfuzz/submodules/nosqli.py,sha256=K0TlBtpfeBH72q01a3TCQnt9OsznA9kfRYVTe7Vmers,9399
142
141
  bbot/modules/lightfuzz/submodules/path.py,sha256=cvfna9P5Cicmc3p3BrzlY0PG1slcvJkeMzZu4i2nwO0,7744
143
- bbot/modules/lightfuzz/submodules/serial.py,sha256=i3TdGV7M0G5thn1SFyKrod9nrm9UPV8kN3sd2-tvmEc,8528
144
- bbot/modules/lightfuzz/submodules/sqli.py,sha256=42TTB3UglMqnlxl7p2lUx14GWjbY9b6X7K9jWB5Mf9I,8486
142
+ bbot/modules/lightfuzz/submodules/serial.py,sha256=Vry3J0Bs3QJqgVPzxhDFmEZQt4FYzLmpOYUHr9tCgR4,9118
143
+ bbot/modules/lightfuzz/submodules/sqli.py,sha256=HX0wP-aVn02zzBDujpLgzXPos7w_eiSiALTNCN2O_Bo,8597
145
144
  bbot/modules/lightfuzz/submodules/ssti.py,sha256=Pib49rXFuf567msnlec-A1Tnvolw4aILjqn7INLWQTY,1413
146
- bbot/modules/lightfuzz/submodules/xss.py,sha256=VP15TBeRjglIRjLvwmHJaOCNQOWS7R4WVAZ-VRNe198,9503
145
+ bbot/modules/lightfuzz/submodules/xss.py,sha256=BZz1_nqzV8dqJptpoqZEMdVBdtZHmRae3HWo3S9yzIc,9507
147
146
  bbot/modules/myssl.py,sha256=DoMF7o6MxIrcglCrC-W3nM-GPcyJRM4PlGdKfnOlIvs,942
148
147
  bbot/modules/newsletters.py,sha256=1Q4JjShPsxHJ-by2CbGfCvEt80blUGPX0hxQIzB_a9M,2630
149
148
  bbot/modules/ntlm.py,sha256=EGmb4k3YC_ZuHIU3mGUZ4yaMjE35wVQQSv8HwTsQJzY,4391
@@ -237,10 +236,10 @@ bbot/presets/web/dirbust-heavy.yml,sha256=NDqu7p0Hx1RsZCVnaEWRgI_iL9O0io-tvWerxJ
237
236
  bbot/presets/web/dirbust-light.yml,sha256=5zSANdjKfYh49kFlsElYY2G6acVrZFzDCEkyqwU6oOQ,203
238
237
  bbot/presets/web/dotnet-audit.yml,sha256=FViiccDXG08P3INNe06bLPeatejbw8Kb1HW5xgdUJNU,520
239
238
  bbot/presets/web/iis-shortnames.yml,sha256=EcYKMpl-cI8Xb79_u4wQS42yFXxDpLH9OqINcFUXoTE,176
240
- bbot/presets/web/lightfuzz-heavy.yml,sha256=a-f11tSUj5NhVQJNm2NJb4OqXV8oPnwnd1kbwepDxHY,466
239
+ bbot/presets/web/lightfuzz-heavy.yml,sha256=zb7DPT-tf5MxTXkVpHn8cx2YwpbaGwZOST8vbhAOWZ0,459
241
240
  bbot/presets/web/lightfuzz-light.yml,sha256=pkjTa5ULeOhCgRYPAoJR-cVfyhErT3I1aqmWGHTIgBk,899
242
- bbot/presets/web/lightfuzz-medium.yml,sha256=e5dKHkiGbLMIw1fTC6lKGH4UpnWit1XtvVdIuFS8dY4,497
243
- bbot/presets/web/lightfuzz-superheavy.yml,sha256=c5x-EpK-xbg-qWxPXLLp3ysKFl1LRhJyl_SlkPVowxQ,857
241
+ bbot/presets/web/lightfuzz-medium.yml,sha256=LUB1Em4EQnIB387E3EiUw4AOIW9kzz3ItMb3xBBYnzE,490
242
+ bbot/presets/web/lightfuzz-superheavy.yml,sha256=3EaiNUCxsRqcrkhMcB70pMkMGT8BplikzSxfosprWTk,850
244
243
  bbot/presets/web/lightfuzz-xss.yml,sha256=LMe968_iKyQhnm1nPh6zXDeNyDum2_MPkLg7ukqr93A,680
245
244
  bbot/presets/web/paramminer.yml,sha256=8n-aDzufrZdtIlZwI0yh4-rQiwU1FPODYwmyra3l-1M,393
246
245
  bbot/presets/web-basic.yml,sha256=6YWSYclbuf9yr8-gILDpLvOUj5QjP4rlarm5_d5iBFw,79
@@ -378,7 +377,7 @@ bbot/test/test_step_2/module_tests/test_module_ipstack.py,sha256=C0Le03UqvShpATo
378
377
  bbot/test/test_step_2/module_tests/test_module_jadx.py,sha256=qTBfDc_Iv03n8iGdyLm6kBaKeEdSxFYeKj5xL1PmyF0,2391
379
378
  bbot/test/test_step_2/module_tests/test_module_json.py,sha256=gmlqge5ZJpjVMGs7OLZBsNlSFTTrKnKjIZMIU23o8VQ,3350
380
379
  bbot/test/test_step_2/module_tests/test_module_leakix.py,sha256=DQaQsL4ewpuYeygp-sgcvdeOSzvHq77_eYjKcgebS7A,1817
381
- bbot/test/test_step_2/module_tests/test_module_lightfuzz.py,sha256=g8rPTtjPe90ZkjCEMlNUC2fraqzZu4XK_0GaA7sGI9A,77463
380
+ bbot/test/test_step_2/module_tests/test_module_lightfuzz.py,sha256=W8IrU5WEBESR8xZUNVHWzLqjDVuVj2m_5q0xiGZwYAo,72050
382
381
  bbot/test/test_step_2/module_tests/test_module_medusa.py,sha256=vYoAyMf0LbIXCoUzLycOISZtF7M58E30WjuLuqxDiCg,1671
383
382
  bbot/test/test_step_2/module_tests/test_module_mysql.py,sha256=4wAPjbjhlxmOkEhQnIQIBC2BLEaE57TX6lChGZ3zLsU,2630
384
383
  bbot/test/test_step_2/module_tests/test_module_myssl.py,sha256=zRJ1sOEespWtBx2jA07bW5sHD1XQ9pV0PtHtGogo7Gs,1531
@@ -452,8 +451,8 @@ bbot/wordlists/raft-small-extensions-lowercase_CLEANED.txt,sha256=ZSIVebs7ptMvHx
452
451
  bbot/wordlists/top_open_ports_nmap.txt,sha256=LmdFYkfapSxn1pVuQC2LkOIY2hMLgG-Xts7DVtYzweM,42727
453
452
  bbot/wordlists/valid_url_schemes.txt,sha256=0B_VAr9Dv7aYhwi6JSBDU-3M76vNtzN0qEC_RNLo7HE,3310
454
453
  bbot/wordlists/wordninja_dns.txt.gz,sha256=DYHvvfW0TvzrVwyprqODAk4tGOxv5ezNmCPSdPuDUnQ,570241
455
- bbot-2.4.2.6706rc0.dist-info/LICENSE,sha256=GzeCzK17hhQQDNow0_r0L8OfLpeTKQjFQwBQU7ZUymg,32473
456
- bbot-2.4.2.6706rc0.dist-info/METADATA,sha256=7rjBEj5pcTefGTU6PY90E3IBhUd5zt-fnQIWvZGoJto,18308
457
- bbot-2.4.2.6706rc0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
458
- bbot-2.4.2.6706rc0.dist-info/entry_points.txt,sha256=cWjvcU_lLrzzJgjcjF7yeGuRA_eDS8pQ-kmPUAyOBfo,38
459
- bbot-2.4.2.6706rc0.dist-info/RECORD,,
454
+ bbot-2.5.0.6715rc0.dist-info/LICENSE,sha256=GzeCzK17hhQQDNow0_r0L8OfLpeTKQjFQwBQU7ZUymg,32473
455
+ bbot-2.5.0.6715rc0.dist-info/METADATA,sha256=RwysEf_RUW3X7xCtPJoRvVHFtoZBYaKOfg6Rs2XMkUI,18308
456
+ bbot-2.5.0.6715rc0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
457
+ bbot-2.5.0.6715rc0.dist-info/entry_points.txt,sha256=cWjvcU_lLrzzJgjcjF7yeGuRA_eDS8pQ-kmPUAyOBfo,38
458
+ bbot-2.5.0.6715rc0.dist-info/RECORD,,
@@ -1,183 +0,0 @@
1
- from .base import BaseLightfuzz
2
- from bbot.errors import HttpCompareError
3
- import urllib.parse
4
-
5
-
6
- class nosqli(BaseLightfuzz):
7
- """
8
- Detects NoSQL injection vulnerabilities.
9
-
10
- Techniques:
11
-
12
- * Quote Injection Analysis:
13
- - Injects single quotes and escaped single quotes into parameters
14
- - Compares response differences between the two to detect NoSQL parsing
15
- - Uses baseline comparison to validate findings and reduce false positives
16
-
17
- * Operator Injection:
18
- - Tests MongoDB-style operator injection using [$eq] and [$ne]
19
- - Modifies parameter names to include operators
20
- - Detects behavioral changes in application responses
21
-
22
- Validation of findings is achieved using confirmation probes to rule out unstable endpoints
23
- """
24
-
25
- friendly_name = "NoSQL Injection"
26
-
27
- async def fuzz(self):
28
- cookies = self.event.data.get("assigned_cookies", {})
29
- probe_value = self.incoming_probe_value(populate_empty=True)
30
- quote_probe_baseline = None
31
- try:
32
- quote_probe_baseline = self.compare_baseline(
33
- self.event.data["type"], probe_value, cookies, additional_params_populate_empty=True
34
- )
35
- except HttpCompareError as e:
36
- self.verbose(f"Encountered HttpCompareError Sending Compare Baseline: {e}")
37
-
38
- if quote_probe_baseline:
39
- try:
40
- # send the with a single quote, and then another with an escaped single quote
41
- (
42
- single_quote_comparison,
43
- single_quote_diff_reasons,
44
- single_quote_reflection,
45
- single_quote_response,
46
- ) = await self.compare_probe(
47
- quote_probe_baseline,
48
- self.event.data["type"],
49
- f"{probe_value}'",
50
- cookies,
51
- additional_params_populate_empty=True,
52
- )
53
- (
54
- escaped_single_quote_comparison,
55
- escaped_single_quote_diff_reasons,
56
- escaped_single_quote_reflection,
57
- escaped_single_quote_response,
58
- ) = await self.compare_probe(
59
- quote_probe_baseline,
60
- self.event.data["type"],
61
- rf"{probe_value}\'",
62
- cookies,
63
- additional_params_populate_empty=True,
64
- )
65
- if not single_quote_comparison and single_quote_response and escaped_single_quote_response:
66
- # if the single quote probe changed the code or body, and the escaped single quote probe did not cause the same change, injection is possible
67
- if ("code" in single_quote_diff_reasons or "body" in single_quote_diff_reasons) and (
68
- single_quote_diff_reasons != escaped_single_quote_diff_reasons
69
- ):
70
- self.verbose(
71
- "Initial heuristic indicates possible NoSQL Injection, sending confirmation probes"
72
- )
73
- confirm_baseline = self.compare_baseline(
74
- self.event.data["type"],
75
- urllib.parse.quote(f"{probe_value}' && 0 && 'x", safe=""),
76
- cookies,
77
- additional_params_populate_empty=True,
78
- skip_urlencoding=True,
79
- )
80
- (
81
- confirmation_probe_false_comparison,
82
- confirmation_probe_false_diff_reasons,
83
- confirmation_probe_false_reflection,
84
- confirmation_probe_false_response,
85
- ) = await self.compare_probe(
86
- confirm_baseline,
87
- self.event.data["type"],
88
- urllib.parse.quote(f"{probe_value}' && 1 && 'x", safe=""),
89
- cookies,
90
- additional_params_populate_empty=True,
91
- skip_urlencoding=True,
92
- )
93
- if confirmation_probe_false_response:
94
- if not confirmation_probe_false_comparison and confirmation_probe_false_diff_reasons != [
95
- "header"
96
- ]:
97
- (
98
- final_confirm_comparison,
99
- final_confirm_diff_reasons,
100
- final_confirm_reflection,
101
- final_confirm_response,
102
- ) = await self.compare_probe(
103
- confirm_baseline,
104
- self.event.data["type"],
105
- urllib.parse.quote(f"{probe_value}' && 0 && 'x", safe=""),
106
- cookies,
107
- additional_params_populate_empty=True,
108
- skip_urlencoding=True,
109
- )
110
-
111
- if final_confirm_response and final_confirm_comparison:
112
- self.results.append(
113
- {
114
- "type": "FINDING",
115
- "description": f"Possible NoSQL Injection. {self.metadata()} Detection Method: [Quote/Escaped Quote + Conditional Affect] Differences: [{'.'.join(confirmation_probe_false_diff_reasons)}]",
116
- }
117
- )
118
- else:
119
- self.verbose(
120
- "Aborted reporting Possible NoSQL Injection, due to unstable/inconsistent responses"
121
- )
122
-
123
- except HttpCompareError as e:
124
- self.verbose(f"Encountered HttpCompareError Sending Compare Probe: {e}")
125
-
126
- # Comparison operator injection
127
- if self.event.data["type"] in ["POSTPARAM", "GETPARAM"]:
128
- nosqli_negation_baseline = None
129
-
130
- try:
131
- nosqli_negation_baseline = self.compare_baseline(
132
- self.event.data["type"],
133
- f"{probe_value}'",
134
- cookies,
135
- additional_params_populate_empty=True,
136
- parameter_name_suffix="[$eq]",
137
- parameter_name_suffix_additional_params="[$eq]",
138
- )
139
- except HttpCompareError as e:
140
- self.verbose(f"Encountered HttpCompareError Sending Compare Baseline: {e}")
141
-
142
- if nosqli_negation_baseline:
143
- try:
144
- (
145
- nosqli_negate_comparison,
146
- nosqli_negate_diff_reasons,
147
- nosqli_negate_reflection,
148
- nosqli_negate_response,
149
- ) = await self.compare_probe(
150
- nosqli_negation_baseline,
151
- self.event.data["type"],
152
- f"{probe_value}'",
153
- cookies,
154
- additional_params_populate_empty=True,
155
- parameter_name_suffix="[$ne]",
156
- parameter_name_suffix_additional_params="[$ne]",
157
- )
158
- if nosqli_negate_response:
159
- if not nosqli_negate_comparison and nosqli_negate_diff_reasons != ["header"]:
160
- # If we are about to report a finding, rule out a false positive from unstable URL by sending another probe with the baseline values, and ensure those dont also come back as different
161
- (
162
- nosqli_negate_comfirm_comparison,
163
- nosqli_negate_confirm_diff_reasons,
164
- nosqli_negate_confirm_reflection,
165
- nosqli_negate_confirm_response,
166
- ) = await self.compare_probe(
167
- nosqli_negation_baseline,
168
- self.event.data["type"],
169
- f"{probe_value}'",
170
- cookies,
171
- additional_params_populate_empty=True,
172
- parameter_name_suffix="[$eq]",
173
- parameter_name_suffix_additional_params="[$eq]",
174
- )
175
- if nosqli_negate_comfirm_comparison:
176
- self.results.append(
177
- {
178
- "type": "FINDING",
179
- "description": f"Possible NoSQL Injection. {self.metadata()} Detection Method: [Parameter Name Operator Injection - Negation ([$ne])] Differences: [{'.'.join(nosqli_negate_diff_reasons)}]",
180
- }
181
- )
182
- except HttpCompareError as e:
183
- self.verbose(f"Encountered HttpCompareError Sending Compare Probe: {e}")