scythe-ttp 0.12.4__py3-none-any.whl → 0.14.0__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 scythe-ttp might be problematic. Click here for more details.
- scythe/auth/__init__.py +3 -1
- scythe/auth/base.py +9 -0
- scythe/auth/cookie_jwt.py +172 -0
- scythe/cli/__init__.py +3 -0
- scythe/cli/main.py +601 -0
- scythe/core/headers.py +69 -9
- scythe/journeys/__init__.py +2 -1
- scythe/journeys/actions.py +235 -1
- scythe/journeys/base.py +161 -12
- scythe/journeys/executor.py +102 -22
- scythe/ttps/web/uuid_guessing.py +3 -2
- {scythe_ttp-0.12.4.dist-info → scythe_ttp-0.14.0.dist-info}/METADATA +84 -16
- {scythe_ttp-0.12.4.dist-info → scythe_ttp-0.14.0.dist-info}/RECORD +17 -13
- scythe_ttp-0.14.0.dist-info/entry_points.txt +2 -0
- {scythe_ttp-0.12.4.dist-info → scythe_ttp-0.14.0.dist-info}/WHEEL +0 -0
- {scythe_ttp-0.12.4.dist-info → scythe_ttp-0.14.0.dist-info}/licenses/LICENSE +0 -0
- {scythe_ttp-0.12.4.dist-info → scythe_ttp-0.14.0.dist-info}/top_level.txt +0 -0
scythe/journeys/executor.py
CHANGED
|
@@ -3,6 +3,7 @@ import logging
|
|
|
3
3
|
from selenium import webdriver
|
|
4
4
|
from selenium.webdriver.chrome.options import Options
|
|
5
5
|
from typing import Optional, Dict, Any, List
|
|
6
|
+
import requests
|
|
6
7
|
from ..behaviors.base import Behavior
|
|
7
8
|
from .base import Journey
|
|
8
9
|
from ..core.headers import HeaderExtractor
|
|
@@ -24,6 +25,10 @@ class JourneyExecutor:
|
|
|
24
25
|
|
|
25
26
|
Similar to TTPExecutor but designed for complex multi-step scenarios
|
|
26
27
|
involving journeys composed of steps and actions.
|
|
28
|
+
|
|
29
|
+
Supports two interaction modes:
|
|
30
|
+
- UI: browser-driven via Selenium (default, backward-compatible)
|
|
31
|
+
- API: REST-driven via requests without starting a browser
|
|
27
32
|
"""
|
|
28
33
|
|
|
29
34
|
def __init__(self,
|
|
@@ -31,7 +36,8 @@ class JourneyExecutor:
|
|
|
31
36
|
target_url: str,
|
|
32
37
|
headless: bool = True,
|
|
33
38
|
behavior: Optional[Behavior] = None,
|
|
34
|
-
driver_options: Optional[Dict[str, Any]] = None
|
|
39
|
+
driver_options: Optional[Dict[str, Any]] = None,
|
|
40
|
+
mode: str = "UI"):
|
|
35
41
|
"""
|
|
36
42
|
Initialize the Journey executor.
|
|
37
43
|
|
|
@@ -45,6 +51,7 @@ class JourneyExecutor:
|
|
|
45
51
|
self.journey = journey
|
|
46
52
|
self.target_url = target_url
|
|
47
53
|
self.behavior = behavior
|
|
54
|
+
self.mode = (mode or "UI").upper()
|
|
48
55
|
self.logger = logging.getLogger(f"Journey.{self.journey.name}")
|
|
49
56
|
|
|
50
57
|
# Setup Chrome options
|
|
@@ -108,29 +115,62 @@ class JourneyExecutor:
|
|
|
108
115
|
self.logger.info(f"Using behavior: {self.behavior.name}")
|
|
109
116
|
self.logger.info(f"Behavior description: {self.behavior.description}")
|
|
110
117
|
|
|
111
|
-
self._setup_driver()
|
|
112
|
-
|
|
113
118
|
try:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
if self.mode == 'API':
|
|
120
|
+
# API mode: no WebDriver, prepare requests session and context
|
|
121
|
+
session = requests.Session()
|
|
122
|
+
auth_headers = {}
|
|
123
|
+
auth_cookies = {}
|
|
124
|
+
if getattr(self.journey, 'authentication', None):
|
|
125
|
+
# Try to obtain headers/cookies directly (no browser flow)
|
|
126
|
+
try:
|
|
127
|
+
auth_headers = self.journey.authentication.get_auth_headers() or {}
|
|
128
|
+
except Exception as e:
|
|
129
|
+
self.logger.warning(f"Failed to get auth headers from authentication: {e}")
|
|
130
|
+
try:
|
|
131
|
+
if hasattr(self.journey.authentication, 'get_auth_cookies'):
|
|
132
|
+
auth_cookies = self.journey.authentication.get_auth_cookies() or {}
|
|
133
|
+
except Exception as e:
|
|
134
|
+
self.logger.warning(f"Failed to get auth cookies from authentication: {e}")
|
|
135
|
+
if auth_headers:
|
|
136
|
+
session.headers.update(auth_headers)
|
|
137
|
+
if auth_cookies:
|
|
138
|
+
for ck, cv in auth_cookies.items():
|
|
139
|
+
try:
|
|
140
|
+
session.cookies.set(ck, cv)
|
|
141
|
+
except Exception:
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
# Seed journey context for API actions
|
|
145
|
+
self.journey.set_context('mode', 'API')
|
|
146
|
+
self.journey.set_context('requests_session', session)
|
|
147
|
+
self.journey.set_context('auth_headers', auth_headers)
|
|
148
|
+
self.journey.set_context('auth_cookies', auth_cookies)
|
|
149
|
+
|
|
150
|
+
# Execute a journey with a None driver (API actions ignore a driver)
|
|
151
|
+
self.execution_results = self.journey.execute(None, self.target_url)
|
|
121
152
|
else:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
153
|
+
# UI mode (default)
|
|
154
|
+
self._setup_driver()
|
|
155
|
+
|
|
156
|
+
# Pre-execution behavior setup
|
|
157
|
+
if self.behavior and self.driver:
|
|
158
|
+
self.behavior.pre_execution(self.driver, self.target_url)
|
|
159
|
+
|
|
160
|
+
# Execute the journey
|
|
161
|
+
if self.driver:
|
|
162
|
+
self.execution_results = self.journey.execute(self.driver, self.target_url)
|
|
163
|
+
else:
|
|
164
|
+
raise RuntimeError("WebDriver not initialized")
|
|
165
|
+
|
|
166
|
+
# Apply behavior timing between steps if configured
|
|
167
|
+
if self.behavior:
|
|
168
|
+
self._apply_behavior_to_journey()
|
|
169
|
+
|
|
170
|
+
# Post-execution behavior cleanup
|
|
171
|
+
if self.behavior and self.driver:
|
|
172
|
+
behavior_results = self._convert_results_for_behavior()
|
|
173
|
+
self.behavior.post_execution(self.driver, behavior_results)
|
|
134
174
|
|
|
135
175
|
except KeyboardInterrupt:
|
|
136
176
|
self.logger.info("Journey interrupted by user.")
|
|
@@ -143,6 +183,7 @@ class JourneyExecutor:
|
|
|
143
183
|
self.execution_results = self._create_error_results(str(e))
|
|
144
184
|
|
|
145
185
|
finally:
|
|
186
|
+
# Cleanup and print summary (driver quit only if initialized)
|
|
146
187
|
self._cleanup()
|
|
147
188
|
|
|
148
189
|
return self.execution_results
|
|
@@ -311,6 +352,45 @@ class JourneyExecutor:
|
|
|
311
352
|
|
|
312
353
|
self.logger.info(f" {status} Step {i}: {step_name} - {result_text} ({expected_text}){version_info}")
|
|
313
354
|
self.logger.info(f" Actions: {len([a for a in actions if a.get('actual', False)])}/{len(actions)} succeeded")
|
|
355
|
+
# Print diagnostic details only for unexpected outcomes
|
|
356
|
+
for a in actions:
|
|
357
|
+
actual = a.get('actual', False)
|
|
358
|
+
expected = a.get('expected', True)
|
|
359
|
+
if actual != expected:
|
|
360
|
+
prefix = "✗ Action failed" if expected else "✗ Action unexpectedly succeeded"
|
|
361
|
+
self.logger.error(f" {prefix}: {a.get('action_name')}")
|
|
362
|
+
ad = a.get('details', {}) or {}
|
|
363
|
+
method = ad.get('request_method')
|
|
364
|
+
url = ad.get('url')
|
|
365
|
+
status_code = ad.get('status_code')
|
|
366
|
+
dur = ad.get('duration_ms')
|
|
367
|
+
parts = []
|
|
368
|
+
if method:
|
|
369
|
+
parts.append(f"method={method}")
|
|
370
|
+
if url:
|
|
371
|
+
parts.append(f"url={url}")
|
|
372
|
+
if status_code is not None:
|
|
373
|
+
parts.append(f"status={status_code}")
|
|
374
|
+
if dur is not None:
|
|
375
|
+
parts.append(f"duration_ms={dur}")
|
|
376
|
+
if parts:
|
|
377
|
+
self.logger.error(" Details: " + ", ".join(parts))
|
|
378
|
+
if ad.get('request_headers'):
|
|
379
|
+
self.logger.error(f" Request headers: {ad.get('request_headers')}")
|
|
380
|
+
if ad.get('request_params'):
|
|
381
|
+
self.logger.error(f" Request params: {ad.get('request_params')}")
|
|
382
|
+
if ad.get('request_json') is not None:
|
|
383
|
+
self.logger.error(f" Request JSON: {ad.get('request_json')}")
|
|
384
|
+
if ad.get('request_data') is not None:
|
|
385
|
+
self.logger.error(f" Request data: {ad.get('request_data')}")
|
|
386
|
+
if ad.get('response_headers'):
|
|
387
|
+
self.logger.error(f" Response headers: {ad.get('response_headers')}")
|
|
388
|
+
if 'response_json' in ad:
|
|
389
|
+
self.logger.error(f" Response JSON: {ad.get('response_json')}")
|
|
390
|
+
elif 'response_text' in ad:
|
|
391
|
+
self.logger.error(f" Response text: {ad.get('response_text')}")
|
|
392
|
+
if ad.get('error'):
|
|
393
|
+
self.logger.error(f" Error: {ad.get('error')}")
|
|
314
394
|
|
|
315
395
|
# Version summary
|
|
316
396
|
target_versions = self.execution_results.get('target_versions', [])
|
scythe/ttps/web/uuid_guessing.py
CHANGED
|
@@ -5,6 +5,7 @@ from ...payloads.generators import PayloadGenerator
|
|
|
5
5
|
import requests
|
|
6
6
|
from uuid import UUID
|
|
7
7
|
|
|
8
|
+
|
|
8
9
|
class GuessUUIDInURL(TTP):
|
|
9
10
|
def __init__(self,
|
|
10
11
|
target_url: str,
|
|
@@ -18,10 +19,10 @@ class GuessUUIDInURL(TTP):
|
|
|
18
19
|
description="simulate bruteforcing UUID's in the URL path",
|
|
19
20
|
expected_result=expected_result,
|
|
20
21
|
authentication=authentication)
|
|
21
|
-
|
|
22
|
+
|
|
22
23
|
self.target_url = target_url
|
|
23
24
|
self.uri_root_path = uri_root_path
|
|
24
|
-
self.payload_generator = payload_generator
|
|
25
|
+
self.payload_generator = payload_generator
|
|
25
26
|
|
|
26
27
|
def get_payloads(self):
|
|
27
28
|
yield from self.payload_generator()
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scythe-ttp
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Summary: An extensible framework for emulating attacker TTPs with Selenium.
|
|
5
|
-
|
|
6
|
-
Author: EpykLab
|
|
7
|
-
Author-email: cyber@epyklab.com
|
|
5
|
+
Author-email: EpykLab <cyber@epyklab.com>
|
|
8
6
|
Classifier: Programming Language :: Python :: 3
|
|
9
7
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
8
|
Classifier: Operating System :: OS Independent
|
|
@@ -13,37 +11,31 @@ Classifier: Intended Audience :: Developers
|
|
|
13
11
|
Classifier: Intended Audience :: Information Technology
|
|
14
12
|
Classifier: Topic :: Security
|
|
15
13
|
Classifier: Framework :: Pytest
|
|
16
|
-
Requires-Python:
|
|
14
|
+
Requires-Python: <=3.13,>=3.8
|
|
17
15
|
Description-Content-Type: text/markdown
|
|
18
16
|
License-File: LICENSE
|
|
17
|
+
Requires-Dist: PySocks==1.7.1
|
|
19
18
|
Requires-Dist: attrs==25.3.0
|
|
20
19
|
Requires-Dist: certifi==2025.6.15
|
|
21
20
|
Requires-Dist: charset-normalizer==3.4.2
|
|
22
21
|
Requires-Dist: h11==0.16.0
|
|
23
22
|
Requires-Dist: idna==3.10
|
|
24
23
|
Requires-Dist: outcome==1.3.0.post0
|
|
25
|
-
Requires-Dist:
|
|
24
|
+
Requires-Dist: pydantic-core==2.18.2
|
|
25
|
+
Requires-Dist: pydantic==2.7.1
|
|
26
26
|
Requires-Dist: requests==2.32.4
|
|
27
27
|
Requires-Dist: selenium==4.34.0
|
|
28
28
|
Requires-Dist: setuptools==80.9.0
|
|
29
29
|
Requires-Dist: sniffio==1.3.1
|
|
30
30
|
Requires-Dist: sortedcontainers==2.4.0
|
|
31
|
-
Requires-Dist: trio==0.30.0
|
|
32
31
|
Requires-Dist: trio-websocket==0.12.2
|
|
32
|
+
Requires-Dist: trio==0.30.0
|
|
33
33
|
Requires-Dist: typing_extensions==4.14.0
|
|
34
34
|
Requires-Dist: urllib3==2.4.0
|
|
35
35
|
Requires-Dist: websocket-client==1.8.0
|
|
36
36
|
Requires-Dist: wsproto==1.2.0
|
|
37
|
-
|
|
38
|
-
Dynamic: author-email
|
|
39
|
-
Dynamic: classifier
|
|
40
|
-
Dynamic: description
|
|
41
|
-
Dynamic: description-content-type
|
|
42
|
-
Dynamic: home-page
|
|
37
|
+
Requires-Dist: typer
|
|
43
38
|
Dynamic: license-file
|
|
44
|
-
Dynamic: requires-dist
|
|
45
|
-
Dynamic: requires-python
|
|
46
|
-
Dynamic: summary
|
|
47
39
|
|
|
48
40
|
<h1 align="center">Scythe</h1>
|
|
49
41
|
|
|
@@ -792,3 +784,79 @@ This architecture supports testing scenarios from simple security checks to comp
|
|
|
792
784
|
---
|
|
793
785
|
|
|
794
786
|
**Scythe**: Comprehensive adverse conditions testing for robust, reliable systems.
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
## Scythe CLI (embedded)
|
|
791
|
+
|
|
792
|
+
Scythe now ships with a lightweight CLI that helps you bootstrap and manage your local Scythe testing workspace. After installing the package (pipx recommended), a `scythe` command is available.
|
|
793
|
+
|
|
794
|
+
Note: The CLI is implemented with Typer, so `scythe --help` and per-command help (e.g., `scythe run --help`) are available. Command names and options remain the same as before.
|
|
795
|
+
|
|
796
|
+
- Install with pipx:
|
|
797
|
+
- pipx install scythe-ttp
|
|
798
|
+
- Or install locally in editable mode for development:
|
|
799
|
+
- pip install -e .
|
|
800
|
+
|
|
801
|
+
### Commands
|
|
802
|
+
|
|
803
|
+
- scythe init [--path PATH]
|
|
804
|
+
- Initializes a Scythe project at PATH (default: current directory).
|
|
805
|
+
- Creates:
|
|
806
|
+
- ./.scythe/scythe.db (SQLite DB with tests and runs tables)
|
|
807
|
+
- ./.scythe/scythe_tests/ (where your test scripts live)
|
|
808
|
+
|
|
809
|
+
- scythe new <name>
|
|
810
|
+
- Creates a new test template at ./.scythe/scythe_tests/<name>.py and registers it in the DB (tests table).
|
|
811
|
+
|
|
812
|
+
- scythe run <name or name.py>
|
|
813
|
+
- Runs the specified test from ./.scythe/scythe_tests and records the run into the DB (runs table). Exit code reflects success (0) or failure (non-zero).
|
|
814
|
+
|
|
815
|
+
- scythe db dump
|
|
816
|
+
- Prints a JSON dump of the tests and runs tables from ./.scythe/scythe.db.
|
|
817
|
+
|
|
818
|
+
- scythe db sync-compat <name>
|
|
819
|
+
- Reads COMPATIBLE_VERSIONS from ./.scythe/scythe_tests/<name>.py (if present) and updates the `tests.compatible_versions` field in the DB. If the variable is missing, the DB entry is set to empty and the command exits successfully.
|
|
820
|
+
|
|
821
|
+
### Test template
|
|
822
|
+
|
|
823
|
+
Created tests use a minimal template so you can start quickly:
|
|
824
|
+
|
|
825
|
+
```python
|
|
826
|
+
#!/usr/bin/env python3
|
|
827
|
+
|
|
828
|
+
# scythe test initial template
|
|
829
|
+
|
|
830
|
+
import argparse
|
|
831
|
+
import os
|
|
832
|
+
import sys
|
|
833
|
+
import time
|
|
834
|
+
from typing import List, Tuple
|
|
835
|
+
|
|
836
|
+
# Scythe framework imports
|
|
837
|
+
from scythe.core.executor import TTPExecutor
|
|
838
|
+
from scythe.behaviors import HumanBehavior
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
def scythe_test_definition(args):
|
|
842
|
+
# TODO: implement your test using Scythe primitives.
|
|
843
|
+
return True
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
def main():
|
|
847
|
+
parser = argparse.ArgumentParser(description="Scythe test script")
|
|
848
|
+
parser.add_argument('--url', help='Target URL (overridden by localhost unless FORCE_USE_CLI_URL=1)')
|
|
849
|
+
args = parser.parse_args()
|
|
850
|
+
|
|
851
|
+
ok = scythe_test_definition(args)
|
|
852
|
+
sys.exit(0 if ok else 1)
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
if __name__ == "__main__":
|
|
856
|
+
main()
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
Notes:
|
|
860
|
+
- The CLI looks for tests in ./.scythe/scythe_tests.
|
|
861
|
+
- Each `run` creates a record in the `runs` table with datetime, name_of_test, x_scythe_target_version (best-effort parsed from output), result, raw_output.
|
|
862
|
+
- Each `new` creates a record in the `tests` table with name, path, created_date, compatible_versions.
|
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
scythe/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
scythe/auth/__init__.py,sha256=
|
|
3
|
-
scythe/auth/base.py,sha256=
|
|
2
|
+
scythe/auth/__init__.py,sha256=InEANqWEIAULFyzH9IyxWDPs_gJd3m_JYmzoaBk_37M,420
|
|
3
|
+
scythe/auth/base.py,sha256=DllKaPGj0MRyRh4PQgQ2TUFgeAXjgXOT2h6zUz2ZAag,3807
|
|
4
4
|
scythe/auth/basic.py,sha256=H4IG9-Y7wFe7ZQCNHmmqhre-Pp9CnBxlT23h2uvOPWo,14354
|
|
5
5
|
scythe/auth/bearer.py,sha256=ngOL-sS6FcfB8XAKMR-CZbpqyySu2MaKxUl10SyBmmI,12687
|
|
6
|
+
scythe/auth/cookie_jwt.py,sha256=z5Q-c594_m-dmh2Rv_4Xfeu0fXSQdlZ12Q-emtyj63g,6337
|
|
6
7
|
scythe/behaviors/__init__.py,sha256=w-WRBGRgna5a1N8oHP2aXSQnkQUHyOXiujpwEVf_ZyM,291
|
|
7
8
|
scythe/behaviors/base.py,sha256=INvIYKVIWzEi5w_4njOwKZ3X9IvySvqiMJnYX7_2Lns,3955
|
|
8
9
|
scythe/behaviors/default.py,sha256=MDx4N-KwC23pPLGu1-ZIkGiTRNUG3Lxjbvo7SJ3UwMc,2117
|
|
9
10
|
scythe/behaviors/human.py,sha256=1PqYvE7cnxlj-KDmDIr3uzfWHvDAbbxQxJ0V0iTl9yo,10291
|
|
10
11
|
scythe/behaviors/machine.py,sha256=NDMUq3mDhpCvujzAFxhn2eSVq78-J-LSBhIcvHkzKXo,4624
|
|
11
12
|
scythe/behaviors/stealth.py,sha256=xv7MrPQgRCdCUJyYTcXV2aasWZoAw8rAQWg-AuQVb7U,15278
|
|
13
|
+
scythe/cli/__init__.py,sha256=9EVxmFiWsAoqWJ6br1bc3BxlA71JyOQP28fUHhX2k7E,43
|
|
14
|
+
scythe/cli/main.py,sha256=ZqkTn2DKro68ODd3jr35QORgglo2RqA9Bw7GZSsY1Y0,21328
|
|
12
15
|
scythe/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
16
|
scythe/core/executor.py,sha256=x1w2nByVu2G70sh7t0kOh6urlrTm_r_pbk0S7v1Ov28,9736
|
|
14
|
-
scythe/core/headers.py,sha256=
|
|
17
|
+
scythe/core/headers.py,sha256=AokCQ3F5QGUcfoK7iO57hA1HHL4IznZeWV464_MqYcE,16670
|
|
15
18
|
scythe/core/ttp.py,sha256=Xw9GgptYsjZ-pMLdyPv64bhiwGKobrXHdF32pjIY7OU,3102
|
|
16
|
-
scythe/journeys/__init__.py,sha256
|
|
17
|
-
scythe/journeys/actions.py,sha256=
|
|
18
|
-
scythe/journeys/base.py,sha256=
|
|
19
|
-
scythe/journeys/executor.py,sha256=
|
|
19
|
+
scythe/journeys/__init__.py,sha256=Odi8NhRg7Hefmo1EJj1guakrCSPhsuus4i-_62uUUjs,654
|
|
20
|
+
scythe/journeys/actions.py,sha256=cDBYdhY5pCXKG-57-op8gH8z9u3_wbIOhwqSZ2Z_jDs,36432
|
|
21
|
+
scythe/journeys/base.py,sha256=vXIgEnSW__iYTriBbuMG4l_XCM96xojJH_fyFScKoBY,24969
|
|
22
|
+
scythe/journeys/executor.py,sha256=_q2hzl4G9iv07I6NVMtNaK3O8QGLDwLNMiaxIle-nsY,24654
|
|
20
23
|
scythe/orchestrators/__init__.py,sha256=_vemcXjKbB1jI0F2dPA0F1zNsyUekjcXImLDUDhWDN0,560
|
|
21
24
|
scythe/orchestrators/base.py,sha256=YOZV0ewlzJ49H08P_LKnimutUms8NnDrQprFpSKhOeM,13595
|
|
22
25
|
scythe/orchestrators/batch.py,sha256=FpK501kk-earJzz6v7dcuw2y708rTvt_IMH_5qjKdrc,26635
|
|
@@ -28,9 +31,10 @@ scythe/ttps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
28
31
|
scythe/ttps/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
32
|
scythe/ttps/web/login_bruteforce.py,sha256=D4G8zB_nU9LD5w3Vv2ABTuOl4XTeg2BgZwYMObt4JJw,2488
|
|
30
33
|
scythe/ttps/web/sql_injection.py,sha256=aWk4DFePbtFDsieOOj03Ux-5OiykyOs2_d_3SvWMOVE,2910
|
|
31
|
-
scythe/ttps/web/uuid_guessing.py,sha256=
|
|
32
|
-
scythe_ttp-0.
|
|
33
|
-
scythe_ttp-0.
|
|
34
|
-
scythe_ttp-0.
|
|
35
|
-
scythe_ttp-0.
|
|
36
|
-
scythe_ttp-0.
|
|
34
|
+
scythe/ttps/web/uuid_guessing.py,sha256=JwNt_9HVynMWFPPU6UGJFcpxvMVDsvc_wAnJVtcYbps,1235
|
|
35
|
+
scythe_ttp-0.14.0.dist-info/licenses/LICENSE,sha256=B7iB4Fv6zDQolC7IgqNF8F4GEp_DLe2jrPPuR_MYMOM,1064
|
|
36
|
+
scythe_ttp-0.14.0.dist-info/METADATA,sha256=mfwhEqF4PYFk7TYCvqHwvqBV90vb9rItOoFa5qLTobU,30161
|
|
37
|
+
scythe_ttp-0.14.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
38
|
+
scythe_ttp-0.14.0.dist-info/entry_points.txt,sha256=rAAsFBcCm0OX3I4uRyclfx4YJGoTuumZKY43HN7R5Ro,48
|
|
39
|
+
scythe_ttp-0.14.0.dist-info/top_level.txt,sha256=BCKTrPuVvmLyhOR07C1ggOh6sU7g2LoVvwDMn46O55Y,7
|
|
40
|
+
scythe_ttp-0.14.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|