opencode-api-security-testing 3.0.8 → 3.0.10
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.
- package/agents/api-cyber-supervisor.md +9 -3
- package/agents/api-probing-miner.md +10 -2
- package/agents/api-resource-specialist.md +44 -35
- package/agents/api-vuln-verifier.md +56 -24
- package/package.json +1 -1
- package/postinstall.mjs +1 -0
- package/preuninstall.mjs +43 -32
- package/src/index.ts +3 -100
- package/README.md +0 -74
- package/SKILL.md +0 -1797
- package/core/advanced_recon.py +0 -788
- package/core/agentic_analyzer.py +0 -445
- package/core/analyzers/api_parser.py +0 -210
- package/core/analyzers/response_analyzer.py +0 -212
- package/core/analyzers/sensitive_finder.py +0 -184
- package/core/api_fuzzer.py +0 -422
- package/core/api_interceptor.py +0 -525
- package/core/api_parser.py +0 -955
- package/core/browser_tester.py +0 -479
- package/core/cloud_storage_tester.py +0 -1330
- package/core/collectors/__init__.py +0 -23
- package/core/collectors/api_path_finder.py +0 -300
- package/core/collectors/browser_collect.py +0 -645
- package/core/collectors/browser_collector.py +0 -411
- package/core/collectors/http_client.py +0 -111
- package/core/collectors/js_collector.py +0 -490
- package/core/collectors/js_parser.py +0 -780
- package/core/collectors/url_collector.py +0 -319
- package/core/context_manager.py +0 -682
- package/core/deep_api_tester_v35.py +0 -844
- package/core/deep_api_tester_v55.py +0 -366
- package/core/dynamic_api_analyzer.py +0 -532
- package/core/http_client.py +0 -179
- package/core/models.py +0 -296
- package/core/orchestrator.py +0 -890
- package/core/prerequisite.py +0 -227
- package/core/reasoning_engine.py +0 -1042
- package/core/response_classifier.py +0 -606
- package/core/runner.py +0 -938
- package/core/scan_engine.py +0 -599
- package/core/skill_executor.py +0 -435
- package/core/skill_executor_v2.py +0 -670
- package/core/skill_executor_v3.py +0 -704
- package/core/smart_analyzer.py +0 -687
- package/core/strategy_pool.py +0 -707
- package/core/testers/auth_tester.py +0 -264
- package/core/testers/idor_tester.py +0 -200
- package/core/testers/sqli_tester.py +0 -211
- package/core/testing_loop.py +0 -655
- package/core/utils/base_path_dict.py +0 -255
- package/core/utils/payload_lib.py +0 -167
- package/core/utils/ssrf_detector.py +0 -220
- package/core/verifiers/vuln_verifier.py +0 -536
- package/references/README.md +0 -72
- package/references/asset-discovery.md +0 -119
- package/references/fuzzing-patterns.md +0 -129
- package/references/graphql-guidance.md +0 -108
- package/references/intake.md +0 -84
- package/references/pua-agent.md +0 -192
- package/references/report-template.md +0 -156
- package/references/rest-guidance.md +0 -76
- package/references/severity-model.md +0 -76
- package/references/test-matrix.md +0 -86
- package/references/validation.md +0 -78
- package/references/vulnerabilities/01-sqli-tests.md +0 -1128
- package/references/vulnerabilities/02-user-enum-tests.md +0 -423
- package/references/vulnerabilities/03-jwt-tests.md +0 -499
- package/references/vulnerabilities/04-idor-tests.md +0 -362
- package/references/vulnerabilities/05-sensitive-data-tests.md +0 -466
- package/references/vulnerabilities/06-biz-logic-tests.md +0 -501
- package/references/vulnerabilities/07-security-config-tests.md +0 -511
- package/references/vulnerabilities/08-brute-force-tests.md +0 -457
- package/references/vulnerabilities/09-vulnerability-chains.md +0 -465
- package/references/vulnerabilities/10-auth-tests.md +0 -537
- package/references/vulnerabilities/11-graphql-tests.md +0 -355
- package/references/vulnerabilities/12-ssrf-tests.md +0 -396
- package/references/vulnerabilities/README.md +0 -148
- package/references/workflows.md +0 -192
- package/src/hooks/directory-agents-injector.ts +0 -106
package/core/strategy_pool.py
DELETED
|
@@ -1,707 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Strategy Pool - 策略池系统
|
|
4
|
-
|
|
5
|
-
动态策略管理:
|
|
6
|
-
- 预定义策略库(8种策略)
|
|
7
|
-
- 策略选择算法
|
|
8
|
-
- 策略适应性调整
|
|
9
|
-
- 策略有效性评估
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
import time
|
|
13
|
-
import json
|
|
14
|
-
from datetime import datetime
|
|
15
|
-
from typing import Dict, List, Set, Optional, Any, Callable
|
|
16
|
-
from dataclasses import dataclass, field
|
|
17
|
-
from enum import Enum
|
|
18
|
-
from collections import defaultdict
|
|
19
|
-
import logging
|
|
20
|
-
|
|
21
|
-
logger = logging.getLogger(__name__)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class StrategyState(Enum):
|
|
25
|
-
"""策略状态"""
|
|
26
|
-
IDLE = "idle"
|
|
27
|
-
ACTIVE = "active"
|
|
28
|
-
PAUSED = "paused"
|
|
29
|
-
COMPLETED = "completed"
|
|
30
|
-
FAILED = "failed"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@dataclass
|
|
34
|
-
class Condition:
|
|
35
|
-
"""策略激活条件"""
|
|
36
|
-
type: str # 'insight_type', 'tech_stack', 'network_status', 'endpoint_score'
|
|
37
|
-
operator: str # 'equals', 'contains', 'greater_than', 'less_than', 'in'
|
|
38
|
-
value: Any
|
|
39
|
-
|
|
40
|
-
def evaluate(self, context: 'StrategyContext') -> bool:
|
|
41
|
-
"""评估条件是否满足"""
|
|
42
|
-
if self.type == 'insight_type':
|
|
43
|
-
insight_types = context.get('insight_types', [])
|
|
44
|
-
if self.operator == 'contains':
|
|
45
|
-
return self.value in insight_types
|
|
46
|
-
elif self.operator == 'in':
|
|
47
|
-
return self.value in insight_types
|
|
48
|
-
|
|
49
|
-
elif self.type == 'tech_stack':
|
|
50
|
-
tech_stack = context.get('tech_stack', {})
|
|
51
|
-
if self.operator == 'contains':
|
|
52
|
-
return self.value in tech_stack
|
|
53
|
-
|
|
54
|
-
elif self.type == 'network_status':
|
|
55
|
-
status = context.get('network_status', 'normal')
|
|
56
|
-
if self.operator == 'equals':
|
|
57
|
-
return status == self.value
|
|
58
|
-
elif self.operator == 'in':
|
|
59
|
-
return status in self.value
|
|
60
|
-
|
|
61
|
-
elif self.type == 'endpoint_score':
|
|
62
|
-
score = context.get('endpoint_score', 0)
|
|
63
|
-
if self.operator == 'greater_than':
|
|
64
|
-
return score > self.value
|
|
65
|
-
elif self.operator == 'greater_equal':
|
|
66
|
-
return score >= self.value
|
|
67
|
-
elif self.operator == 'equals':
|
|
68
|
-
return score == self.value
|
|
69
|
-
|
|
70
|
-
elif self.type == 'endpoint_type':
|
|
71
|
-
endpoint_path = context.get('endpoint_path', '').lower()
|
|
72
|
-
if self.operator == 'contains':
|
|
73
|
-
return self.value in endpoint_path
|
|
74
|
-
|
|
75
|
-
elif self.type == 'waf_detected':
|
|
76
|
-
waf = context.get('waf_detected')
|
|
77
|
-
if self.operator == 'equals':
|
|
78
|
-
return waf == self.value
|
|
79
|
-
elif self.operator == 'is_not_none':
|
|
80
|
-
return waf is not None
|
|
81
|
-
|
|
82
|
-
elif self.type == 'is_spa':
|
|
83
|
-
is_spa = context.get('is_spa', False)
|
|
84
|
-
return is_spa == self.value
|
|
85
|
-
|
|
86
|
-
elif self.type == 'has_internal_ips':
|
|
87
|
-
internal_ips = context.get('internal_ips', set())
|
|
88
|
-
return len(internal_ips) > 0 if self.value else len(internal_ips) == 0
|
|
89
|
-
|
|
90
|
-
return False
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@dataclass
|
|
94
|
-
class Action:
|
|
95
|
-
"""策略动作"""
|
|
96
|
-
type: str # 'test_sqli', 'test_xss', 'fuzz_path', etc.
|
|
97
|
-
params: Dict[str, Any] = field(default_factory=dict)
|
|
98
|
-
priority: int = 0
|
|
99
|
-
timeout: float = 30.0
|
|
100
|
-
retry_on_failure: int = 1
|
|
101
|
-
|
|
102
|
-
def to_dict(self) -> Dict:
|
|
103
|
-
return {
|
|
104
|
-
'type': self.type,
|
|
105
|
-
'params': self.params,
|
|
106
|
-
'priority': self.priority,
|
|
107
|
-
'timeout': self.timeout,
|
|
108
|
-
'retry_on_failure': self.retry_on_failure
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
@dataclass
|
|
113
|
-
class StrategyMetrics:
|
|
114
|
-
"""策略指标"""
|
|
115
|
-
success_count: int = 0
|
|
116
|
-
failure_count: int = 0
|
|
117
|
-
total_executions: int = 0
|
|
118
|
-
avg_effectiveness: float = 0.0
|
|
119
|
-
last_execution_time: Optional[datetime] = None
|
|
120
|
-
last_success_time: Optional[datetime] = None
|
|
121
|
-
|
|
122
|
-
def record_execution(self, success: bool, effectiveness: float = 0.0):
|
|
123
|
-
"""记录执行结果"""
|
|
124
|
-
self.total_executions += 1
|
|
125
|
-
if success:
|
|
126
|
-
self.success_count += 1
|
|
127
|
-
self.last_success_time = datetime.now()
|
|
128
|
-
else:
|
|
129
|
-
self.failure_count += 1
|
|
130
|
-
|
|
131
|
-
if self.total_executions > 0:
|
|
132
|
-
self.avg_effectiveness = (
|
|
133
|
-
(self.avg_effectiveness * (self.total_executions - 1) + effectiveness)
|
|
134
|
-
/ self.total_executions
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
self.last_execution_time = datetime.now()
|
|
138
|
-
|
|
139
|
-
def to_dict(self) -> Dict:
|
|
140
|
-
return {
|
|
141
|
-
'success_count': self.success_count,
|
|
142
|
-
'failure_count': self.failure_count,
|
|
143
|
-
'total_executions': self.total_executions,
|
|
144
|
-
'avg_effectiveness': self.avg_effectiveness,
|
|
145
|
-
'last_execution_time': self.last_execution_time.isoformat() if self.last_execution_time else None,
|
|
146
|
-
'success_rate': self.success_count / max(self.total_executions, 1)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
@dataclass
|
|
151
|
-
class Strategy:
|
|
152
|
-
"""策略"""
|
|
153
|
-
id: str
|
|
154
|
-
name: str
|
|
155
|
-
description: str
|
|
156
|
-
|
|
157
|
-
activation_conditions: List[Condition] = field(default_factory=list)
|
|
158
|
-
priority: int = 0
|
|
159
|
-
|
|
160
|
-
actions: List[Action] = field(default_factory=list)
|
|
161
|
-
execution_order: str = "sequential" # 'sequential', 'parallel', 'adaptive'
|
|
162
|
-
|
|
163
|
-
exit_on: List[str] = field(default_factory=list) # 'all_complete', 'vuln_found', 'blocked'
|
|
164
|
-
max_duration: float = 300.0
|
|
165
|
-
max_iterations: int = 100
|
|
166
|
-
|
|
167
|
-
is_adaptive: bool = False
|
|
168
|
-
adaptation_threshold: float = 0.3
|
|
169
|
-
|
|
170
|
-
state: StrategyState = StrategyState.IDLE
|
|
171
|
-
metrics: StrategyMetrics = field(default_factory=StrategyMetrics)
|
|
172
|
-
|
|
173
|
-
config: Dict[str, Any] = field(default_factory=dict)
|
|
174
|
-
|
|
175
|
-
def is_active(self) -> bool:
|
|
176
|
-
return self.state == StrategyState.ACTIVE
|
|
177
|
-
|
|
178
|
-
def can_activate(self, context: 'StrategyContext') -> bool:
|
|
179
|
-
"""检查是否可以激活"""
|
|
180
|
-
if not self.activation_conditions:
|
|
181
|
-
return True
|
|
182
|
-
|
|
183
|
-
for cond in self.activation_conditions:
|
|
184
|
-
if not cond.evaluate(context):
|
|
185
|
-
return False
|
|
186
|
-
|
|
187
|
-
return True
|
|
188
|
-
|
|
189
|
-
def should_exit(self, exit_reason: str, vulns_found: int = 0) -> bool:
|
|
190
|
-
"""检查是否应该退出"""
|
|
191
|
-
if exit_reason in self.exit_on:
|
|
192
|
-
return True
|
|
193
|
-
|
|
194
|
-
if 'vuln_found' in self.exit_on and vulns_found > 0:
|
|
195
|
-
return True
|
|
196
|
-
|
|
197
|
-
return False
|
|
198
|
-
|
|
199
|
-
def to_dict(self) -> Dict:
|
|
200
|
-
return {
|
|
201
|
-
'id': self.id,
|
|
202
|
-
'name': self.name,
|
|
203
|
-
'description': self.description,
|
|
204
|
-
'priority': self.priority,
|
|
205
|
-
'state': self.state.value,
|
|
206
|
-
'metrics': self.metrics.to_dict(),
|
|
207
|
-
'actions': [a.to_dict() for a in self.actions],
|
|
208
|
-
'config': self.config
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
class StrategyContext(Dict):
|
|
213
|
-
"""策略上下文(字典-like)"""
|
|
214
|
-
|
|
215
|
-
def get(self, key: str, default: Any = None) -> Any:
|
|
216
|
-
try:
|
|
217
|
-
return self[key]
|
|
218
|
-
except KeyError:
|
|
219
|
-
return default
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
@dataclass
|
|
223
|
-
class StrategyPlan:
|
|
224
|
-
"""策略计划"""
|
|
225
|
-
primary_strategy: Strategy
|
|
226
|
-
fallback_strategy: Optional[Strategy] = None
|
|
227
|
-
|
|
228
|
-
execution_order: List[str] = field(default_factory=list)
|
|
229
|
-
adaptations: Dict[str, Any] = field(default_factory=dict)
|
|
230
|
-
|
|
231
|
-
estimated_duration: float = 0.0
|
|
232
|
-
estimated_actions: int = 0
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
class StrategyPool:
|
|
236
|
-
"""
|
|
237
|
-
策略池
|
|
238
|
-
|
|
239
|
-
包含预定义策略库和策略选择逻辑
|
|
240
|
-
"""
|
|
241
|
-
|
|
242
|
-
def __init__(self):
|
|
243
|
-
self.strategies: Dict[str, Strategy] = {}
|
|
244
|
-
self._register_default_strategies()
|
|
245
|
-
|
|
246
|
-
def _register_default_strategies(self):
|
|
247
|
-
"""注册默认策略"""
|
|
248
|
-
self.register_strategy(self._create_default_strategy())
|
|
249
|
-
self.register_strategy(self._create_waf_bypass_strategy())
|
|
250
|
-
self.register_strategy(self._create_spa_fallback_strategy())
|
|
251
|
-
self.register_strategy(self._create_internal_address_strategy())
|
|
252
|
-
self.register_strategy(self._create_high_value_endpoint_strategy())
|
|
253
|
-
self.register_strategy(self._create_auth_testing_strategy())
|
|
254
|
-
self.register_strategy(self._create_rate_limited_strategy())
|
|
255
|
-
self.register_strategy(self._create_sensitive_operation_strategy())
|
|
256
|
-
|
|
257
|
-
def register_strategy(self, strategy: Strategy):
|
|
258
|
-
"""注册策略"""
|
|
259
|
-
self.strategies[strategy.id] = strategy
|
|
260
|
-
logger.debug(f"Registered strategy: {strategy.id}")
|
|
261
|
-
|
|
262
|
-
def get_strategy(self, strategy_id: str) -> Optional[Strategy]:
|
|
263
|
-
"""获取策略"""
|
|
264
|
-
return self.strategies.get(strategy_id)
|
|
265
|
-
|
|
266
|
-
def get_all_strategies(self) -> List[Strategy]:
|
|
267
|
-
"""获取所有策略"""
|
|
268
|
-
return list(self.strategies.values())
|
|
269
|
-
|
|
270
|
-
def select_strategy(self, context: StrategyContext, insights: List[Any] = None) -> Strategy:
|
|
271
|
-
"""
|
|
272
|
-
根据上下文选择最佳策略
|
|
273
|
-
|
|
274
|
-
选择逻辑:
|
|
275
|
-
1. 检查所有可激活策略
|
|
276
|
-
2. 按优先级排序
|
|
277
|
-
3. 返回最高优先级策略
|
|
278
|
-
"""
|
|
279
|
-
if insights is None:
|
|
280
|
-
insights = []
|
|
281
|
-
|
|
282
|
-
context['insight_types'] = [i.type for i in insights] if hasattr(insights, '__iter__') else []
|
|
283
|
-
|
|
284
|
-
activatable = []
|
|
285
|
-
for strategy in self.strategies.values():
|
|
286
|
-
if strategy.can_activate(context):
|
|
287
|
-
activatable.append((strategy.priority, strategy.id, strategy))
|
|
288
|
-
|
|
289
|
-
if not activatable:
|
|
290
|
-
return self.strategies['default']
|
|
291
|
-
|
|
292
|
-
activatable.sort(key=lambda x: x[0], reverse=True)
|
|
293
|
-
|
|
294
|
-
selected = activatable[0][2]
|
|
295
|
-
selected.state = StrategyState.ACTIVE
|
|
296
|
-
|
|
297
|
-
logger.info(f"Selected strategy: {selected.id} ({selected.name})")
|
|
298
|
-
|
|
299
|
-
return selected
|
|
300
|
-
|
|
301
|
-
def select_multiple(self, context: StrategyContext, max_strategies: int = 3) -> List[Strategy]:
|
|
302
|
-
"""选择多个策略"""
|
|
303
|
-
activatable = []
|
|
304
|
-
for strategy in self.strategies.values():
|
|
305
|
-
if strategy.can_activate(context):
|
|
306
|
-
activatable.append((strategy.priority, id(strategy), strategy))
|
|
307
|
-
|
|
308
|
-
if not activatable:
|
|
309
|
-
return [self.strategies['default']]
|
|
310
|
-
|
|
311
|
-
activatable.sort(key=lambda x: x[0], reverse=True)
|
|
312
|
-
|
|
313
|
-
return [s[2] for s in activatable[:max_strategies]]
|
|
314
|
-
|
|
315
|
-
def create_plan(self, context: StrategyContext, insights: List[Any] = None) -> StrategyPlan:
|
|
316
|
-
"""创建策略计划"""
|
|
317
|
-
primary = self.select_strategy(context, insights)
|
|
318
|
-
|
|
319
|
-
estimated_actions = len(primary.actions)
|
|
320
|
-
estimated_duration = sum(a.timeout for a in primary.actions)
|
|
321
|
-
|
|
322
|
-
return StrategyPlan(
|
|
323
|
-
primary_strategy=primary,
|
|
324
|
-
fallback_strategy=self.strategies.get('default'),
|
|
325
|
-
execution_order=[primary.id],
|
|
326
|
-
estimated_duration=estimated_duration,
|
|
327
|
-
estimated_actions=estimated_actions
|
|
328
|
-
)
|
|
329
|
-
|
|
330
|
-
def adapt_strategy(self, strategy: Strategy, feedback: Dict) -> Strategy:
|
|
331
|
-
"""根据反馈调整策略"""
|
|
332
|
-
if not strategy.is_adaptive:
|
|
333
|
-
return strategy
|
|
334
|
-
|
|
335
|
-
effectiveness = feedback.get('effectiveness', 0.0)
|
|
336
|
-
|
|
337
|
-
if effectiveness < strategy.adaptation_threshold:
|
|
338
|
-
for action in strategy.actions:
|
|
339
|
-
if action.type == 'test_sqli' or action.type == 'test_xss':
|
|
340
|
-
action.params['use_bypass'] = True
|
|
341
|
-
action.params['obfuscation_level'] = 'high'
|
|
342
|
-
|
|
343
|
-
return strategy
|
|
344
|
-
|
|
345
|
-
def record_outcome(self, strategy_id: str, success: bool, effectiveness: float = 0.0):
|
|
346
|
-
"""记录策略执行结果"""
|
|
347
|
-
strategy = self.strategies.get(strategy_id)
|
|
348
|
-
if strategy:
|
|
349
|
-
strategy.metrics.record_execution(success, effectiveness)
|
|
350
|
-
|
|
351
|
-
if success:
|
|
352
|
-
logger.info(f"Strategy {strategy_id} succeeded (effectiveness: {effectiveness:.2f})")
|
|
353
|
-
else:
|
|
354
|
-
logger.warning(f"Strategy {strategy_id} failed")
|
|
355
|
-
|
|
356
|
-
def _create_default_strategy(self) -> Strategy:
|
|
357
|
-
"""创建默认策略"""
|
|
358
|
-
return Strategy(
|
|
359
|
-
id='default',
|
|
360
|
-
name='默认测试策略',
|
|
361
|
-
description='适用于大多数目标的默认测试策略',
|
|
362
|
-
priority=0,
|
|
363
|
-
actions=[
|
|
364
|
-
Action(type='discover_endpoints', priority=10),
|
|
365
|
-
Action(type='test_sqli', priority=8),
|
|
366
|
-
Action(type='test_xss', priority=8),
|
|
367
|
-
Action(type='test_auth', priority=6),
|
|
368
|
-
],
|
|
369
|
-
execution_order='sequential',
|
|
370
|
-
exit_on=['all_complete', 'vuln_found', 'blocked'],
|
|
371
|
-
config={
|
|
372
|
-
'rate_limit': 10,
|
|
373
|
-
'payload_set': 'standard',
|
|
374
|
-
'depth': 'normal'
|
|
375
|
-
}
|
|
376
|
-
)
|
|
377
|
-
|
|
378
|
-
def _create_waf_bypass_strategy(self) -> Strategy:
|
|
379
|
-
"""创建 WAF 绕过策略"""
|
|
380
|
-
return Strategy(
|
|
381
|
-
id='waf_detected',
|
|
382
|
-
name='WAF 绕过策略',
|
|
383
|
-
description='当检测到 WAF 时使用的绕过策略',
|
|
384
|
-
priority=10,
|
|
385
|
-
activation_conditions=[
|
|
386
|
-
Condition(type='waf_detected', operator='is_not_none', value=None)
|
|
387
|
-
],
|
|
388
|
-
actions=[
|
|
389
|
-
Action(type='test_sqli_bypass', priority=10, params={'obfuscation_level': 'high'}),
|
|
390
|
-
Action(type='test_xss_bypass', priority=10, params={'obfuscation_level': 'high'}),
|
|
391
|
-
Action(type='test_obfuscated', priority=8),
|
|
392
|
-
],
|
|
393
|
-
execution_order='sequential',
|
|
394
|
-
exit_on=['all_complete', 'vuln_found', 'blocked'],
|
|
395
|
-
is_adaptive=True,
|
|
396
|
-
adaptation_threshold=0.3,
|
|
397
|
-
config={
|
|
398
|
-
'rate_limit': 2,
|
|
399
|
-
'payload_set': 'waf_bypass',
|
|
400
|
-
'depth': 'normal'
|
|
401
|
-
}
|
|
402
|
-
)
|
|
403
|
-
|
|
404
|
-
def _create_spa_fallback_strategy(self) -> Strategy:
|
|
405
|
-
"""创建 SPA Fallback 策略"""
|
|
406
|
-
return Strategy(
|
|
407
|
-
id='spa_fallback',
|
|
408
|
-
name='SPA 深度分析策略',
|
|
409
|
-
description='检测到 SPA fallback 行为时,深度分析 JS',
|
|
410
|
-
priority=20,
|
|
411
|
-
activation_conditions=[
|
|
412
|
-
Condition(type='is_spa', operator='equals', value=True)
|
|
413
|
-
],
|
|
414
|
-
actions=[
|
|
415
|
-
Action(type='extract_js', priority=10),
|
|
416
|
-
Action(type='analyze_webpack', priority=9),
|
|
417
|
-
Action(type='find_api_urls', priority=9),
|
|
418
|
-
Action(type='test_from_js', priority=8),
|
|
419
|
-
Action(type='test_backend_direct', priority=7),
|
|
420
|
-
],
|
|
421
|
-
execution_order='sequential',
|
|
422
|
-
exit_on=['all_complete', 'api_found', 'timeout'],
|
|
423
|
-
config={
|
|
424
|
-
'rate_limit': 5,
|
|
425
|
-
'js_depth': 3,
|
|
426
|
-
'focus': 'reconnaissance'
|
|
427
|
-
}
|
|
428
|
-
)
|
|
429
|
-
|
|
430
|
-
def _create_internal_address_strategy(self) -> Strategy:
|
|
431
|
-
"""创建内网地址策略"""
|
|
432
|
-
return Strategy(
|
|
433
|
-
id='internal_address',
|
|
434
|
-
name='内网代理策略',
|
|
435
|
-
description='发现内网地址时提示配置代理',
|
|
436
|
-
priority=30,
|
|
437
|
-
activation_conditions=[
|
|
438
|
-
Condition(type='has_internal_ips', operator='equals', value=True)
|
|
439
|
-
],
|
|
440
|
-
actions=[
|
|
441
|
-
Action(type='mark_unreachable', priority=10),
|
|
442
|
-
Action(type='extract_testable_apis', priority=9),
|
|
443
|
-
Action(type='suggest_proxy', priority=8),
|
|
444
|
-
],
|
|
445
|
-
execution_order='sequential',
|
|
446
|
-
exit_on=['all_complete'],
|
|
447
|
-
config={
|
|
448
|
-
'rate_limit': 0,
|
|
449
|
-
'requires_user_action': True
|
|
450
|
-
}
|
|
451
|
-
)
|
|
452
|
-
|
|
453
|
-
def _create_high_value_endpoint_strategy(self) -> Strategy:
|
|
454
|
-
"""创建高价值端点策略"""
|
|
455
|
-
return Strategy(
|
|
456
|
-
id='high_value_endpoint',
|
|
457
|
-
name='高价值端点深度测试',
|
|
458
|
-
description='对高评分端点进行深度测试',
|
|
459
|
-
priority=15,
|
|
460
|
-
activation_conditions=[
|
|
461
|
-
Condition(type='endpoint_score', operator='greater_than', value=7)
|
|
462
|
-
],
|
|
463
|
-
actions=[
|
|
464
|
-
Action(type='full_test_suite', priority=10),
|
|
465
|
-
Action(type='test_edge_cases', priority=9),
|
|
466
|
-
Action(type='bypass_auth', priority=8),
|
|
467
|
-
Action(type='test_idor', priority=7),
|
|
468
|
-
],
|
|
469
|
-
execution_order='sequential',
|
|
470
|
-
exit_on=['all_complete', 'vuln_found'],
|
|
471
|
-
is_adaptive=True,
|
|
472
|
-
config={
|
|
473
|
-
'rate_limit': 5,
|
|
474
|
-
'depth': 'maximum',
|
|
475
|
-
'timeout_multiplier': 2.0
|
|
476
|
-
}
|
|
477
|
-
)
|
|
478
|
-
|
|
479
|
-
def _create_auth_testing_strategy(self) -> Strategy:
|
|
480
|
-
"""创建认证测试策略"""
|
|
481
|
-
return Strategy(
|
|
482
|
-
id='auth_testing',
|
|
483
|
-
name='认证安全专项',
|
|
484
|
-
description='针对认证接口的专项测试',
|
|
485
|
-
priority=25,
|
|
486
|
-
activation_conditions=[
|
|
487
|
-
Condition(type='endpoint_type', operator='contains', value='auth'),
|
|
488
|
-
Condition(type='endpoint_type', operator='contains', value='login'),
|
|
489
|
-
],
|
|
490
|
-
actions=[
|
|
491
|
-
Action(type='test_default_creds', priority=10),
|
|
492
|
-
Action(type='test_auth_bypass', priority=9),
|
|
493
|
-
Action(type='test_jwt', priority=9),
|
|
494
|
-
Action(type='test_session', priority=8),
|
|
495
|
-
],
|
|
496
|
-
execution_order='sequential',
|
|
497
|
-
exit_on=['all_complete', 'vuln_found', 'locked'],
|
|
498
|
-
is_adaptive=True,
|
|
499
|
-
config={
|
|
500
|
-
'rate_limit': 3,
|
|
501
|
-
'safety_mode': True,
|
|
502
|
-
'max_attempts': 5
|
|
503
|
-
}
|
|
504
|
-
)
|
|
505
|
-
|
|
506
|
-
def _create_rate_limited_strategy(self) -> Strategy:
|
|
507
|
-
"""创建限速自适应策略"""
|
|
508
|
-
return Strategy(
|
|
509
|
-
id='rate_limited',
|
|
510
|
-
name='限速自适应策略',
|
|
511
|
-
description='检测到限速时自动降速',
|
|
512
|
-
priority=40,
|
|
513
|
-
activation_conditions=[
|
|
514
|
-
Condition(type='network_status', operator='equals', value='rate_limited')
|
|
515
|
-
],
|
|
516
|
-
actions=[
|
|
517
|
-
Action(type='reduce_rate', priority=10),
|
|
518
|
-
Action(type='rotate_user_agent', priority=9),
|
|
519
|
-
Action(type='use_proxy', priority=8),
|
|
520
|
-
],
|
|
521
|
-
execution_order='sequential',
|
|
522
|
-
exit_on=['rate_restored', 'blocked'],
|
|
523
|
-
config={
|
|
524
|
-
'rate_limit': 1,
|
|
525
|
-
'cooldown': 60,
|
|
526
|
-
'backoff_factor': 0.5
|
|
527
|
-
}
|
|
528
|
-
)
|
|
529
|
-
|
|
530
|
-
def _create_sensitive_operation_strategy(self) -> Strategy:
|
|
531
|
-
"""创建敏感操作策略"""
|
|
532
|
-
return Strategy(
|
|
533
|
-
id='sensitive_operation',
|
|
534
|
-
name='敏感操作安全策略',
|
|
535
|
-
description='测试敏感操作时使用最小化原则',
|
|
536
|
-
priority=35,
|
|
537
|
-
activation_conditions=[
|
|
538
|
-
Condition(type='endpoint_type', operator='contains', value='pay'),
|
|
539
|
-
Condition(type='endpoint_type', operator='contains', value='transfer'),
|
|
540
|
-
],
|
|
541
|
-
actions=[
|
|
542
|
-
Action(type='minimal_testing', priority=10),
|
|
543
|
-
Action(type='simulate_normal_usage', priority=9),
|
|
544
|
-
Action(type='avoid_destructive', priority=8),
|
|
545
|
-
],
|
|
546
|
-
execution_order='sequential',
|
|
547
|
-
exit_on=['all_complete'],
|
|
548
|
-
config={
|
|
549
|
-
'rate_limit': 1,
|
|
550
|
-
'safety_mode': True,
|
|
551
|
-
'require_confirmation': True
|
|
552
|
-
}
|
|
553
|
-
)
|
|
554
|
-
|
|
555
|
-
def get_summary(self) -> Dict:
|
|
556
|
-
"""获取策略池摘要"""
|
|
557
|
-
return {
|
|
558
|
-
'total_strategies': len(self.strategies),
|
|
559
|
-
'strategies': {
|
|
560
|
-
k: v.to_dict() for k, v in self.strategies.items()
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
class Strategist:
|
|
566
|
-
"""
|
|
567
|
-
策略师
|
|
568
|
-
|
|
569
|
-
负责:
|
|
570
|
-
- 创建策略计划
|
|
571
|
-
- 评估策略有效性
|
|
572
|
-
- 管理策略执行
|
|
573
|
-
"""
|
|
574
|
-
|
|
575
|
-
def __init__(self, strategy_pool: Optional[StrategyPool] = None):
|
|
576
|
-
self.strategy_pool = strategy_pool or StrategyPool()
|
|
577
|
-
self.current_plan: Optional[StrategyPlan] = None
|
|
578
|
-
self.execution_history: List[Dict] = []
|
|
579
|
-
|
|
580
|
-
def create_strategy_plan(self, context: Dict, insights: List[Any] = None) -> StrategyPlan:
|
|
581
|
-
"""创建策略计划"""
|
|
582
|
-
strategy_context = StrategyContext(context)
|
|
583
|
-
self.current_plan = self.strategy_pool.create_plan(strategy_context, insights)
|
|
584
|
-
|
|
585
|
-
return self.current_plan
|
|
586
|
-
|
|
587
|
-
def evaluate_effectiveness(self, strategy: Strategy, results: Dict) -> float:
|
|
588
|
-
"""
|
|
589
|
-
评估策略有效性
|
|
590
|
-
|
|
591
|
-
基于:
|
|
592
|
-
- 发现漏洞数量
|
|
593
|
-
- 测试覆盖率
|
|
594
|
-
- 执行时间
|
|
595
|
-
- 误报率
|
|
596
|
-
"""
|
|
597
|
-
vuln_count = results.get('vulnerabilities_found', 0)
|
|
598
|
-
coverage = results.get('coverage', 0.0)
|
|
599
|
-
execution_time = results.get('execution_time', 0.0)
|
|
600
|
-
false_positive_rate = results.get('false_positive_rate', 0.0)
|
|
601
|
-
|
|
602
|
-
vuln_weight = 0.4
|
|
603
|
-
coverage_weight = 0.3
|
|
604
|
-
time_weight = 0.1
|
|
605
|
-
accuracy_weight = 0.2
|
|
606
|
-
|
|
607
|
-
vuln_score = min(vuln_count / 10.0, 1.0)
|
|
608
|
-
coverage_score = coverage
|
|
609
|
-
time_score = 1.0 if execution_time < 300 else 0.5
|
|
610
|
-
accuracy_score = 1.0 - false_positive_rate
|
|
611
|
-
|
|
612
|
-
effectiveness = (
|
|
613
|
-
vuln_score * vuln_weight +
|
|
614
|
-
coverage_score * coverage_weight +
|
|
615
|
-
time_score * time_weight +
|
|
616
|
-
accuracy_score * accuracy_weight
|
|
617
|
-
)
|
|
618
|
-
|
|
619
|
-
return effectiveness
|
|
620
|
-
|
|
621
|
-
def should_switch_strategy(self, current: Strategy, new: Strategy, feedback: Dict) -> bool:
|
|
622
|
-
"""判断是否应该切换策略"""
|
|
623
|
-
effectiveness = feedback.get('effectiveness', 0.0)
|
|
624
|
-
|
|
625
|
-
if effectiveness < current.adaptation_threshold:
|
|
626
|
-
return True
|
|
627
|
-
|
|
628
|
-
if current.state == StrategyState.FAILED:
|
|
629
|
-
return True
|
|
630
|
-
|
|
631
|
-
if current.should_exit(feedback.get('exit_reason', '')):
|
|
632
|
-
return True
|
|
633
|
-
|
|
634
|
-
return new.priority > current.priority
|
|
635
|
-
|
|
636
|
-
def record_execution(self, strategy_id: str, results: Dict):
|
|
637
|
-
"""记录策略执行"""
|
|
638
|
-
effectiveness = self.evaluate_effectiveness(
|
|
639
|
-
self.strategy_pool.get_strategy(strategy_id) or Strategy(id=strategy_id, name=strategy_id, description=""),
|
|
640
|
-
results
|
|
641
|
-
)
|
|
642
|
-
|
|
643
|
-
success = effectiveness > 0.3
|
|
644
|
-
|
|
645
|
-
self.strategy_pool.record_outcome(strategy_id, success, effectiveness)
|
|
646
|
-
|
|
647
|
-
self.execution_history.append({
|
|
648
|
-
'strategy_id': strategy_id,
|
|
649
|
-
'effectiveness': effectiveness,
|
|
650
|
-
'success': success,
|
|
651
|
-
'timestamp': datetime.now().isoformat(),
|
|
652
|
-
'results': results
|
|
653
|
-
})
|
|
654
|
-
|
|
655
|
-
def get_best_strategy_for_context(self, context: StrategyContext) -> Strategy:
|
|
656
|
-
"""获取最佳策略"""
|
|
657
|
-
return self.strategy_pool.select_strategy(context)
|
|
658
|
-
|
|
659
|
-
def suggest_alternatives(self, context: StrategyContext) -> List[Strategy]:
|
|
660
|
-
"""建议备选策略"""
|
|
661
|
-
return self.strategy_pool.select_multiple(context, max_strategies=3)
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
def create_strategy_pool() -> StrategyPool:
|
|
665
|
-
"""创建策略池工厂函数"""
|
|
666
|
-
return StrategyPool()
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
def create_strategist(strategy_pool: Optional[StrategyPool] = None) -> Strategist:
|
|
670
|
-
"""创建策略师工厂函数"""
|
|
671
|
-
return Strategist(strategy_pool)
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
if __name__ == "__main__":
|
|
675
|
-
pool = create_strategy_pool()
|
|
676
|
-
|
|
677
|
-
context = StrategyContext({
|
|
678
|
-
'is_spa': True,
|
|
679
|
-
'waf_detected': 'aliyun',
|
|
680
|
-
'network_status': 'normal',
|
|
681
|
-
'endpoint_score': 8,
|
|
682
|
-
'tech_stack': {'vue', 'spring'},
|
|
683
|
-
'insight_types': ['spa_fallback', 'waf_detected']
|
|
684
|
-
})
|
|
685
|
-
|
|
686
|
-
print("=" * 60)
|
|
687
|
-
print("Strategy Pool Demo")
|
|
688
|
-
print("=" * 60)
|
|
689
|
-
|
|
690
|
-
selected = pool.select_strategy(context)
|
|
691
|
-
print(f"\nSelected: {selected.name} ({selected.id})")
|
|
692
|
-
print(f"Priority: {selected.priority}")
|
|
693
|
-
print(f"Actions: {[a.type for a in selected.actions]}")
|
|
694
|
-
print(f"Config: {selected.config}")
|
|
695
|
-
|
|
696
|
-
print("\n" + "-" * 60)
|
|
697
|
-
print("Alternative strategies for this context:")
|
|
698
|
-
alternatives = pool.select_multiple(context, max_strategies=3)
|
|
699
|
-
for i, s in enumerate(alternatives, 1):
|
|
700
|
-
print(f" {i}. {s.name} (priority: {s.priority})")
|
|
701
|
-
|
|
702
|
-
print("\n" + "-" * 60)
|
|
703
|
-
print("Strategy Pool Summary:")
|
|
704
|
-
summary = pool.get_summary()
|
|
705
|
-
print(f"Total strategies: {summary['total_strategies']}")
|
|
706
|
-
for sid, sdata in summary['strategies'].items():
|
|
707
|
-
print(f" - {sid}: {sdata['name']} (state: {sdata['state']})")
|