scythe-ttp 0.16.1__py3-none-any.whl → 0.17.1__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/cli/main.py CHANGED
@@ -68,6 +68,19 @@ def check_version_in_response_header(args) -> bool:
68
68
  def scythe_test_definition(args) -> bool:
69
69
  # TODO: implement your test using Scythe primitives.
70
70
  # Example placeholder that simply passes.
71
+
72
+ # Example usage with TTPExecutor:
73
+ # from scythe.core.executor import TTPExecutor
74
+ # executor = TTPExecutor(ttp=my_ttp, target_url=args.url)
75
+ # executor.run()
76
+ # return executor.was_successful() # Returns True if all results matched expectations
77
+
78
+ # Example usage with JourneyExecutor:
79
+ # from scythe.journeys.executor import JourneyExecutor
80
+ # executor = JourneyExecutor(journey=my_journey, target_url=args.url)
81
+ # executor.run()
82
+ # return executor.was_successful() # Returns True if journey succeeded as expected
83
+
71
84
  return True
72
85
 
73
86
 
@@ -83,6 +96,138 @@ def main():
83
96
  dest='gate_versions',
84
97
  help='Gate versions to test against')
85
98
 
99
+ # Core Application Parameters
100
+ parser.add_argument(
101
+ '--protocol',
102
+ default='https',
103
+ choices=['http', 'https'],
104
+ help='Protocol to use (http/https, default: https)')
105
+ parser.add_argument(
106
+ '--port',
107
+ type=int,
108
+ help='Port number for the target application')
109
+
110
+ # Authentication Parameters
111
+ parser.add_argument(
112
+ '--username',
113
+ help='Username for authentication')
114
+ parser.add_argument(
115
+ '--password',
116
+ help='Password for authentication')
117
+ parser.add_argument(
118
+ '--token',
119
+ help='Bearer token or API key')
120
+ parser.add_argument(
121
+ '--auth-type',
122
+ choices=['basic', 'bearer', 'form'],
123
+ help='Authentication method (basic, bearer, form, etc.)')
124
+ parser.add_argument(
125
+ '--credentials-file',
126
+ help='Path to file containing multiple user credentials')
127
+
128
+ # Test Data Parameters
129
+ parser.add_argument(
130
+ '--users-file',
131
+ help='Path to CSV file containing user data')
132
+ parser.add_argument(
133
+ '--emails-file',
134
+ help='Path to text file containing email addresses')
135
+ parser.add_argument(
136
+ '--payload-file',
137
+ help='Path to file containing test payloads')
138
+ parser.add_argument(
139
+ '--data-file',
140
+ help='Generic path to test data file')
141
+
142
+ # Execution Control Parameters
143
+ parser.add_argument(
144
+ '--batch-size',
145
+ type=int,
146
+ default=10,
147
+ help='Number of operations per batch (default: 10)')
148
+ parser.add_argument(
149
+ '--max-batches',
150
+ type=int,
151
+ help='Maximum number of batches to run')
152
+ parser.add_argument(
153
+ '--workers',
154
+ type=int,
155
+ help='Number of concurrent workers/threads')
156
+ parser.add_argument(
157
+ '--replications',
158
+ type=int,
159
+ help='Number of test replications for load testing')
160
+ parser.add_argument(
161
+ '--timeout',
162
+ type=int,
163
+ help='Request timeout in seconds')
164
+ parser.add_argument(
165
+ '--delay',
166
+ type=float,
167
+ help='Delay between requests in seconds')
168
+
169
+ # Browser/Execution Parameters
170
+ parser.add_argument(
171
+ '--headless',
172
+ action='store_true',
173
+ help='Run browser in headless mode (flag)')
174
+ parser.add_argument(
175
+ '--browser',
176
+ choices=['chrome', 'firefox', 'safari', 'edge'],
177
+ help='Browser type (chrome, firefox, etc.)')
178
+ parser.add_argument(
179
+ '--user-agent',
180
+ help='Custom user agent string')
181
+ parser.add_argument(
182
+ '--proxy',
183
+ help='Proxy server URL')
184
+ parser.add_argument(
185
+ '--proxy-file',
186
+ help='Path to file containing proxy list')
187
+
188
+ # Output and Reporting Parameters
189
+ parser.add_argument(
190
+ '--output-dir',
191
+ help='Directory for output files')
192
+ parser.add_argument(
193
+ '--report-format',
194
+ choices=['json', 'csv', 'html'],
195
+ help='Report format (json, csv, html)')
196
+ parser.add_argument(
197
+ '--log-level',
198
+ choices=['debug', 'info', 'warning', 'error'],
199
+ help='Logging level (debug, info, warning, error)')
200
+ parser.add_argument(
201
+ '--verbose',
202
+ action='store_true',
203
+ help='Enable verbose output (flag)')
204
+ parser.add_argument(
205
+ '--silent',
206
+ action='store_true',
207
+ help='Suppress output except errors (flag)')
208
+
209
+ # Test Control Parameters
210
+ parser.add_argument(
211
+ '--fail-fast',
212
+ action='store_true',
213
+ help='Stop immediately on first failure (flag)')
214
+ parser.add_argument(
215
+ '--dry-run',
216
+ action='store_true',
217
+ help='Validate configuration without executing tests (flag)')
218
+ parser.add_argument(
219
+ '--test-type',
220
+ choices=['load', 'security', 'functional'],
221
+ help='Type of test to run (load, security, functional)')
222
+ parser.add_argument(
223
+ '--iterations',
224
+ type=int,
225
+ help='Number of test iterations')
226
+ parser.add_argument(
227
+ '--duration',
228
+ type=int,
229
+ help='Test duration in seconds')
230
+
86
231
  args = parser.parse_args()
87
232
 
88
233
  if check_url_available(args.url):
scythe/core/executor.py CHANGED
@@ -40,6 +40,7 @@ class TTPExecutor:
40
40
  self.driver = None
41
41
  self.results = []
42
42
  self.header_extractor = HeaderExtractor()
43
+ self.has_test_failures = False # Track if any test had unexpected results
43
44
 
44
45
  def _setup_driver(self):
45
46
  """Initializes the WebDriver."""
@@ -134,10 +135,12 @@ class TTPExecutor:
134
135
  else:
135
136
  version_info = f" | Version: {target_version}" if target_version else ""
136
137
  self.logger.warning(f"UNEXPECTED SUCCESS: '{payload}' (expected to fail){version_info}")
138
+ self.has_test_failures = True # Mark as failure when result differs from expected
137
139
  else:
138
140
  consecutive_failures += 1
139
141
  if self.ttp.expected_result:
140
142
  self.logger.info(f"EXPECTED FAILURE: '{payload}' (security control working)")
143
+ self.has_test_failures = True # Mark as failure when result differs from expected
141
144
  else:
142
145
  self.logger.info(f"EXPECTED FAILURE: '{payload}'")
143
146
 
@@ -212,3 +215,18 @@ class TTPExecutor:
212
215
  self.logger.info("No successes detected (expected to find vulnerabilities).")
213
216
  else:
214
217
  self.logger.info("No successes detected (security controls working as expected).")
218
+
219
+ # Log overall test status
220
+ if self.has_test_failures:
221
+ self.logger.error("\n✗ TEST FAILED: One or more test results differed from expected")
222
+ else:
223
+ self.logger.info("\n✓ TEST PASSED: All test results matched expectations")
224
+
225
+ def was_successful(self) -> bool:
226
+ """
227
+ Check if all test results matched expectations.
228
+
229
+ Returns:
230
+ True if all test results matched expectations, False otherwise
231
+ """
232
+ return not self.has_test_failures
@@ -406,6 +406,12 @@ class JourneyExecutor:
406
406
  else:
407
407
  self.logger.info("\nNo X-SCYTHE-TARGET-VERSION headers detected in responses.")
408
408
 
409
+ # Log overall test status (similar to TTPExecutor)
410
+ if self.was_successful():
411
+ self.logger.info("\n✓ TEST PASSED: Journey results matched expectations")
412
+ else:
413
+ self.logger.error("\n✗ TEST FAILED: Journey results differed from expected")
414
+
409
415
  self.logger.info("="*60)
410
416
 
411
417
  def get_results(self) -> Optional[Dict[str, Any]]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scythe-ttp
3
- Version: 0.16.1
3
+ Version: 0.17.1
4
4
  Summary: An extensible framework for emulating attacker TTPs with Selenium.
5
5
  Author-email: EpykLab <cyber@epyklab.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -35,6 +35,7 @@ Requires-Dist: urllib3==2.4.0
35
35
  Requires-Dist: websocket-client==1.8.0
36
36
  Requires-Dist: wsproto==1.2.0
37
37
  Requires-Dist: typer
38
+ Requires-Dist: shellingham
38
39
  Dynamic: license-file
39
40
 
40
41
  <h1 align="center">Scythe</h1>
@@ -11,15 +11,15 @@ scythe/behaviors/human.py,sha256=1PqYvE7cnxlj-KDmDIr3uzfWHvDAbbxQxJ0V0iTl9yo,102
11
11
  scythe/behaviors/machine.py,sha256=NDMUq3mDhpCvujzAFxhn2eSVq78-J-LSBhIcvHkzKXo,4624
12
12
  scythe/behaviors/stealth.py,sha256=xv7MrPQgRCdCUJyYTcXV2aasWZoAw8rAQWg-AuQVb7U,15278
13
13
  scythe/cli/__init__.py,sha256=9EVxmFiWsAoqWJ6br1bc3BxlA71JyOQP28fUHhX2k7E,43
14
- scythe/cli/main.py,sha256=-PXmdzYzlS5KWndVd35CoxAK17wxfLEmF_KUotJrHc0,21373
14
+ scythe/cli/main.py,sha256=DFvOB39tX4FeiOxitJwXfq28J13GjewBZ9gOA_0HOjI,26003
15
15
  scythe/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- scythe/core/executor.py,sha256=x1w2nByVu2G70sh7t0kOh6urlrTm_r_pbk0S7v1Ov28,9736
16
+ scythe/core/executor.py,sha256=C3FkW-DNugv82T0_ky-3zAvHV_hFwVSHrX2nzgAcmAI,10588
17
17
  scythe/core/headers.py,sha256=AokCQ3F5QGUcfoK7iO57hA1HHL4IznZeWV464_MqYcE,16670
18
18
  scythe/core/ttp.py,sha256=Xw9GgptYsjZ-pMLdyPv64bhiwGKobrXHdF32pjIY7OU,3102
19
19
  scythe/journeys/__init__.py,sha256=Odi8NhRg7Hefmo1EJj1guakrCSPhsuus4i-_62uUUjs,654
20
20
  scythe/journeys/actions.py,sha256=k9WjfGR1nhJWyhDU_lHr7vFy5qAl7hyyV6kCL7ZQRMo,37479
21
21
  scythe/journeys/base.py,sha256=vXIgEnSW__iYTriBbuMG4l_XCM96xojJH_fyFScKoBY,24969
22
- scythe/journeys/executor.py,sha256=_q2hzl4G9iv07I6NVMtNaK3O8QGLDwLNMiaxIle-nsY,24654
22
+ scythe/journeys/executor.py,sha256=uJkjO3PALSLZh3IOSxgX18gRJX_Bck3gW9OClusiQeE,24949
23
23
  scythe/orchestrators/__init__.py,sha256=_vemcXjKbB1jI0F2dPA0F1zNsyUekjcXImLDUDhWDN0,560
24
24
  scythe/orchestrators/base.py,sha256=YOZV0ewlzJ49H08P_LKnimutUms8NnDrQprFpSKhOeM,13595
25
25
  scythe/orchestrators/batch.py,sha256=FpK501kk-earJzz6v7dcuw2y708rTvt_IMH_5qjKdrc,26635
@@ -32,9 +32,9 @@ scythe/ttps/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  scythe/ttps/web/login_bruteforce.py,sha256=D4G8zB_nU9LD5w3Vv2ABTuOl4XTeg2BgZwYMObt4JJw,2488
33
33
  scythe/ttps/web/sql_injection.py,sha256=aWk4DFePbtFDsieOOj03Ux-5OiykyOs2_d_3SvWMOVE,2910
34
34
  scythe/ttps/web/uuid_guessing.py,sha256=JwNt_9HVynMWFPPU6UGJFcpxvMVDsvc_wAnJVtcYbps,1235
35
- scythe_ttp-0.16.1.dist-info/licenses/LICENSE,sha256=B7iB4Fv6zDQolC7IgqNF8F4GEp_DLe2jrPPuR_MYMOM,1064
36
- scythe_ttp-0.16.1.dist-info/METADATA,sha256=LxmrtQniVraYXKXFAlrTE66DYvHC-vGQNp6Wk6HmCDA,30161
37
- scythe_ttp-0.16.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
- scythe_ttp-0.16.1.dist-info/entry_points.txt,sha256=rAAsFBcCm0OX3I4uRyclfx4YJGoTuumZKY43HN7R5Ro,48
39
- scythe_ttp-0.16.1.dist-info/top_level.txt,sha256=BCKTrPuVvmLyhOR07C1ggOh6sU7g2LoVvwDMn46O55Y,7
40
- scythe_ttp-0.16.1.dist-info/RECORD,,
35
+ scythe_ttp-0.17.1.dist-info/licenses/LICENSE,sha256=B7iB4Fv6zDQolC7IgqNF8F4GEp_DLe2jrPPuR_MYMOM,1064
36
+ scythe_ttp-0.17.1.dist-info/METADATA,sha256=bZTf4pApqa3-NNPv6PkktiBPKSgiOOhjv0a7DJmn7To,30188
37
+ scythe_ttp-0.17.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
+ scythe_ttp-0.17.1.dist-info/entry_points.txt,sha256=rAAsFBcCm0OX3I4uRyclfx4YJGoTuumZKY43HN7R5Ro,48
39
+ scythe_ttp-0.17.1.dist-info/top_level.txt,sha256=BCKTrPuVvmLyhOR07C1ggOh6sU7g2LoVvwDMn46O55Y,7
40
+ scythe_ttp-0.17.1.dist-info/RECORD,,