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.
Files changed (79) hide show
  1. package/agents/api-cyber-supervisor.md +9 -3
  2. package/agents/api-probing-miner.md +10 -2
  3. package/agents/api-resource-specialist.md +44 -35
  4. package/agents/api-vuln-verifier.md +56 -24
  5. package/package.json +1 -1
  6. package/postinstall.mjs +1 -0
  7. package/preuninstall.mjs +43 -32
  8. package/src/index.ts +3 -100
  9. package/README.md +0 -74
  10. package/SKILL.md +0 -1797
  11. package/core/advanced_recon.py +0 -788
  12. package/core/agentic_analyzer.py +0 -445
  13. package/core/analyzers/api_parser.py +0 -210
  14. package/core/analyzers/response_analyzer.py +0 -212
  15. package/core/analyzers/sensitive_finder.py +0 -184
  16. package/core/api_fuzzer.py +0 -422
  17. package/core/api_interceptor.py +0 -525
  18. package/core/api_parser.py +0 -955
  19. package/core/browser_tester.py +0 -479
  20. package/core/cloud_storage_tester.py +0 -1330
  21. package/core/collectors/__init__.py +0 -23
  22. package/core/collectors/api_path_finder.py +0 -300
  23. package/core/collectors/browser_collect.py +0 -645
  24. package/core/collectors/browser_collector.py +0 -411
  25. package/core/collectors/http_client.py +0 -111
  26. package/core/collectors/js_collector.py +0 -490
  27. package/core/collectors/js_parser.py +0 -780
  28. package/core/collectors/url_collector.py +0 -319
  29. package/core/context_manager.py +0 -682
  30. package/core/deep_api_tester_v35.py +0 -844
  31. package/core/deep_api_tester_v55.py +0 -366
  32. package/core/dynamic_api_analyzer.py +0 -532
  33. package/core/http_client.py +0 -179
  34. package/core/models.py +0 -296
  35. package/core/orchestrator.py +0 -890
  36. package/core/prerequisite.py +0 -227
  37. package/core/reasoning_engine.py +0 -1042
  38. package/core/response_classifier.py +0 -606
  39. package/core/runner.py +0 -938
  40. package/core/scan_engine.py +0 -599
  41. package/core/skill_executor.py +0 -435
  42. package/core/skill_executor_v2.py +0 -670
  43. package/core/skill_executor_v3.py +0 -704
  44. package/core/smart_analyzer.py +0 -687
  45. package/core/strategy_pool.py +0 -707
  46. package/core/testers/auth_tester.py +0 -264
  47. package/core/testers/idor_tester.py +0 -200
  48. package/core/testers/sqli_tester.py +0 -211
  49. package/core/testing_loop.py +0 -655
  50. package/core/utils/base_path_dict.py +0 -255
  51. package/core/utils/payload_lib.py +0 -167
  52. package/core/utils/ssrf_detector.py +0 -220
  53. package/core/verifiers/vuln_verifier.py +0 -536
  54. package/references/README.md +0 -72
  55. package/references/asset-discovery.md +0 -119
  56. package/references/fuzzing-patterns.md +0 -129
  57. package/references/graphql-guidance.md +0 -108
  58. package/references/intake.md +0 -84
  59. package/references/pua-agent.md +0 -192
  60. package/references/report-template.md +0 -156
  61. package/references/rest-guidance.md +0 -76
  62. package/references/severity-model.md +0 -76
  63. package/references/test-matrix.md +0 -86
  64. package/references/validation.md +0 -78
  65. package/references/vulnerabilities/01-sqli-tests.md +0 -1128
  66. package/references/vulnerabilities/02-user-enum-tests.md +0 -423
  67. package/references/vulnerabilities/03-jwt-tests.md +0 -499
  68. package/references/vulnerabilities/04-idor-tests.md +0 -362
  69. package/references/vulnerabilities/05-sensitive-data-tests.md +0 -466
  70. package/references/vulnerabilities/06-biz-logic-tests.md +0 -501
  71. package/references/vulnerabilities/07-security-config-tests.md +0 -511
  72. package/references/vulnerabilities/08-brute-force-tests.md +0 -457
  73. package/references/vulnerabilities/09-vulnerability-chains.md +0 -465
  74. package/references/vulnerabilities/10-auth-tests.md +0 -537
  75. package/references/vulnerabilities/11-graphql-tests.md +0 -355
  76. package/references/vulnerabilities/12-ssrf-tests.md +0 -396
  77. package/references/vulnerabilities/README.md +0 -148
  78. package/references/workflows.md +0 -192
  79. package/src/hooks/directory-agents-injector.ts +0 -106
@@ -1,435 +0,0 @@
1
- """
2
- SKILL 执行器 - 智能决策执行
3
-
4
- 根据 SKILL.md 定义的决策流程:
5
- 1. 根据前置检查选择模块
6
- 2. 根据静态分析结果判断站点类型
7
- 3. 根据父路径探测结果决定后续行动
8
- 4. 智能跳过/继续测试
9
- """
10
-
11
- import sys
12
- sys.path.insert(0, '/workspace/skill-play/API-Security-Testing-Optimized')
13
-
14
- from core.prerequisite import prerequisite_check
15
- from core.api_parser import APIEndpointParser
16
- from core.cloud_storage_tester import CloudStorageTester
17
-
18
-
19
- class SKILLExecutor:
20
- """SKILL 执行器 - 智能决策执行"""
21
-
22
- def __init__(self, target: str):
23
- self.target = target
24
- self.session = None
25
- self.playwright_available = False
26
- self.browser_type = None
27
-
28
- # 资产发现结果
29
- self.parser = None # 共享的 parser 实例
30
- self.js_files = []
31
- self.static_endpoints = []
32
- self.dynamic_endpoints = []
33
- self.hooked_endpoints = []
34
- self.parent_paths = {}
35
-
36
- # 测试结果
37
- self.vulnerabilities = []
38
- self.cloud_findings = []
39
- self.api_prefix = None
40
-
41
- # 决策状态
42
- self.site_type = None # pure_html / jquery_spa / vue_spa / react_spa / login_required
43
- self.has_real_api = False
44
- self.has_nginx_fallback = False
45
-
46
- def run(self):
47
- """执行 SKILL 流程"""
48
- print("=" * 70)
49
- print(" API Security Testing Skill - 智能执行")
50
- print("=" * 70)
51
- print(f" 目标: {self.target}")
52
- print()
53
-
54
- # ========== 阶段 0: 前置检查 ==========
55
- print("[阶段 0] 前置检查")
56
- print("-" * 50)
57
- self._check_prerequisites()
58
-
59
- if not self.playwright_available:
60
- print(" [WARN] Playwright 不可用,使用受限模式")
61
-
62
- # ========== 阶段 1: 资产发现 - 静态分析 ==========
63
- print("\n[阶段 1] 资产发现 - 静态分析")
64
- print("-" * 50)
65
- self._static_analysis()
66
-
67
- # ========== 阶段 1.1: 判断站点类型 ==========
68
- print("\n[决策] 判断站点类型")
69
- print("-" * 50)
70
- self._detect_site_type()
71
-
72
- # ========== 阶段 1.2: 父路径探测 ==========
73
- print("\n[阶段 1.2] 父路径探测")
74
- print("-" * 50)
75
- self._probe_parent_paths()
76
-
77
- # ========== 阶段 1.3: 根据决策选择下一步 ==========
78
- print("\n[决策] 选择后续行动")
79
- print("-" * 50)
80
- self._decide_next_action()
81
-
82
- # ========== 阶段 2: 漏洞分析 ==========
83
- if self.has_real_api:
84
- print("\n[阶段 2] 漏洞分析")
85
- print("-" * 50)
86
- self._vulnerability_testing()
87
- else:
88
- print("\n[阶段 2] 漏洞分析 - [SKIP]")
89
- print("-" * 50)
90
- print(" 无真实 API 或 nginx fallback,跳过漏洞测试")
91
- self._report_nginx_fallback()
92
-
93
- # ========== 阶段 3: 云存储测试 ==========
94
- print("\n[阶段 3] 云存储测试")
95
- print("-" * 50)
96
- self._cloud_storage_test()
97
-
98
- # ========== 阶段 4: 报告 ==========
99
- print("\n[阶段 4] 报告")
100
- print("-" * 50)
101
- self._generate_report()
102
-
103
- return self._get_result()
104
-
105
- def _check_prerequisites(self):
106
- """前置检查"""
107
- self.playwright_available, self.browser_type, can_proceed = prerequisite_check()
108
-
109
- if can_proceed:
110
- import requests
111
- self.session = requests.Session()
112
- self.session.headers.update({'User-Agent': 'Mozilla/5.0'})
113
- print(" [OK] 前置检查通过")
114
- else:
115
- print(" [FAIL] 前置检查失败")
116
-
117
- def _static_analysis(self):
118
- """静态分析"""
119
- # 使用共享的 parser 实例,避免重复 discover_js_files
120
- self.parser = APIEndpointParser(self.target, self.session)
121
-
122
- # 发现 JS 文件
123
- self.js_files = self.parser.discover_js_files()
124
- print(f" JS 文件: {len(self.js_files)}")
125
-
126
- # 解析端点
127
- self.static_endpoints = self.parser.parse_js_files(self.js_files)
128
- print(f" 静态端点: {len(self.static_endpoints)}")
129
-
130
- for ep in self.static_endpoints[:5]:
131
- print(f" {ep.method} {ep.path}")
132
-
133
- # 统计端点类型
134
- path_apis = sum(1 for ep in self.static_endpoints if '/api/' in ep.path)
135
- print(f" 含 /api/ 路径: {path_apis}")
136
-
137
- def _detect_site_type(self):
138
- """判断站点类型"""
139
- # 检测前端框架(从 JS 文件内容或 HTML)
140
- html = self.session.get(self.target, timeout=10).text.lower()
141
-
142
- frontend = 'Unknown'
143
- ui = 'Unknown'
144
-
145
- # 从 HTML 检测
146
- if 'vue' in html:
147
- frontend = 'Vue.js'
148
- if 'react' in html:
149
- frontend = 'React'
150
- if 'angular' in html:
151
- frontend = 'Angular'
152
- if 'jquery' in html:
153
- frontend = 'jQuery'
154
-
155
- if 'element-ui' in html or 'element ui' in html:
156
- ui = 'ElementUI'
157
- if 'ant-design' in html:
158
- ui = 'Ant Design'
159
-
160
- # 根据 JS 文件数量和端点特征判断站点类型
161
- if len(self.js_files) == 0:
162
- self.site_type = 'pure_html'
163
- print(f" 站点类型: 纯 HTML (无 JS)")
164
- elif frontend == 'Unknown' and len(self.js_files) > 0:
165
- # 可能是 JS 渲染的 SPA(HTML 不包含框架关键字)
166
- self.site_type = 'modern_spa'
167
- frontend = 'Vue.js/React (推断)'
168
- print(f" 站点类型: 现代 SPA (基于 JS 文件)")
169
- elif frontend in ['Vue.js', 'React', 'Angular']:
170
- self.site_type = 'modern_spa'
171
- print(f" 站点类型: 现代 SPA ({frontend})")
172
- elif frontend == 'jQuery':
173
- self.site_type = 'jquery_spa'
174
- print(f" 站点类型: jQuery SPA")
175
- else:
176
- self.site_type = 'unknown'
177
- print(f" 站点类型: 未知")
178
-
179
- print(f" 前端框架: {frontend}")
180
- print(f" UI 框架: {ui}")
181
- print(f" JS 文件: {len(self.js_files)}")
182
-
183
- # 决策:是否需要动态分析
184
- if self.site_type in ['modern_spa', 'jquery_spa'] or len(self.js_files) > 0:
185
- print(f" [建议] 启用动态分析 (发现 {len(self.js_files)} 个 JS 文件)")
186
- else:
187
- print(f" [建议] 可跳过动态分析")
188
-
189
- def _probe_parent_paths(self):
190
- """父路径探测 - 使用共享的 parser 实例"""
191
- # parser.parse_js_files 已经提取了父路径
192
- self.parent_paths = self.parser.probe_parent_paths()
193
-
194
- real_apis = sum(1 for p in self.parent_paths.values() if p.get('is_api'))
195
- html_fallback = sum(1 for p in self.parent_paths.values() if not p.get('is_api'))
196
-
197
- print(f" 父路径: {len(self.parent_paths)}")
198
- print(f" JSON API: {real_apis}")
199
- print(f" HTML fallback: {html_fallback}")
200
-
201
- if real_apis > 0:
202
- self.has_real_api = True
203
- print(f" [OK] 发现真实 API")
204
- else:
205
- self.has_real_api = False
206
- if html_fallback > 0:
207
- self.has_nginx_fallback = True
208
- print(f" [WARN] nginx fallback")
209
- else:
210
- print(f" [INFO] 未发现 API 响应")
211
-
212
- # 保存检测到的 API 前缀
213
- for p in self.parent_paths.values():
214
- if p.get('prefix'):
215
- self.api_prefix = p.get('prefix')
216
- print(f" [API Prefix] {self.api_prefix}")
217
- break
218
-
219
- def _decide_next_action(self):
220
- """决策后续行动"""
221
- print("\n 决策分析:")
222
-
223
- # 决策 1: 是否执行动态分析
224
- if self.site_type in ['modern_spa', 'jquery_spa'] and self.playwright_available:
225
- print(" - [执行] 动态分析 (SPA 站点)")
226
- self._dynamic_analysis()
227
- else:
228
- skip_reason = []
229
- if self.site_type not in ['modern_spa', 'jquery_spa']:
230
- skip_reason.append("非 SPA")
231
- if not self.playwright_available:
232
- skip_reason.append("Playwright 不可用")
233
- print(f" - [跳过] 动态分析 ({', '.join(skip_reason)})")
234
-
235
- # 决策 2: 是否执行 API Hook
236
- if self.playwright_available and self.has_real_api:
237
- print(" - [执行] API Hook (有真实 API)")
238
- self._api_hook()
239
- else:
240
- skip_reason = []
241
- if not self.playwright_available:
242
- skip_reason.append("Playwright 不可用")
243
- if not self.has_real_api:
244
- skip_reason.append("无真实 API")
245
- print(f" - [跳过] API Hook ({', '.join(skip_reason)})")
246
-
247
- # 决策 3: 是否执行漏洞测试
248
- if self.has_real_api:
249
- print(" - [执行] 漏洞测试 (有真实 API)")
250
- else:
251
- print(" - [跳过] 漏洞测试 (无真实 API)")
252
-
253
- def _dynamic_analysis(self):
254
- """动态分析"""
255
- print("\n [动态分析] 启动 Playwright...")
256
- try:
257
- from core.dynamic_api_analyzer import DynamicAPIAnalyzer
258
-
259
- analyzer = DynamicAPIAnalyzer(self.target)
260
- results = analyzer.analyze_full()
261
-
262
- count = len(results.get('endpoints', []))
263
- print(f" [动态分析] 发现 {count} 个端点")
264
-
265
- self.dynamic_endpoints = results.get('endpoints', [])
266
-
267
- except Exception as e:
268
- print(f" [动态分析] 失败: {e}")
269
-
270
- def _api_hook(self):
271
- """API Hook"""
272
- print("\n [API Hook] 启动 Hook...")
273
- try:
274
- from core.api_interceptor import APIInterceptor
275
-
276
- interceptor = APIInterceptor(self.target)
277
- results = interceptor.hook_all_apis()
278
-
279
- count = len(results.get('endpoints', []))
280
- print(f" [API Hook] 捕获 {count} 个 API 调用")
281
-
282
- self.hooked_endpoints = results.get('endpoints', [])
283
-
284
- except Exception as e:
285
- print(f" [API Hook] 失败: {e}")
286
-
287
- def _vulnerability_testing(self):
288
- """漏洞测试"""
289
- print(" [漏洞测试] 执行...")
290
-
291
- # 合并所有端点(统一格式)
292
- all_endpoints = []
293
-
294
- # 静态端点
295
- for ep in self.static_endpoints:
296
- all_endpoints.append({
297
- 'path': ep.path,
298
- 'method': ep.method,
299
- })
300
-
301
- # 动态端点
302
- for ep in self.dynamic_endpoints:
303
- all_endpoints.append({
304
- 'path': ep.get('path', ''),
305
- 'method': ep.get('method', 'GET'),
306
- })
307
-
308
- # Hook 端点
309
- for ep in self.hooked_endpoints:
310
- all_endpoints.append({
311
- 'path': ep.get('path', ''),
312
- 'method': ep.get('method', 'GET'),
313
- })
314
-
315
- # 去重
316
- seen = set()
317
- unique_endpoints = []
318
- for ep in all_endpoints:
319
- key = f"{ep['method']}:{ep['path']}"
320
- if key not in seen and ep['path']:
321
- seen.add(key)
322
- unique_endpoints.append(ep)
323
-
324
- print(f" 总端点: {len(unique_endpoints)}")
325
-
326
- # 简化测试:只测 SQL 注入
327
- sqli_payloads = ["' OR '1'='1"]
328
-
329
- for ep in unique_endpoints[:10]:
330
- path = ep['path']
331
- method = ep['method']
332
-
333
- if method != 'GET':
334
- continue
335
-
336
- # 使用完整 URL(包含 API 前缀)
337
- if self.api_prefix:
338
- url = f"http://{self.target.replace('http://', '').split('/')[0]}{self.api_prefix}{path.lstrip('/')}"
339
- else:
340
- url = self.target.rstrip('/') + path
341
-
342
- if '?' not in url:
343
- url = url + '?id=1'
344
-
345
- try:
346
- r = self.session.get(url.replace('id=1', sqli_payloads[0]), timeout=5)
347
- ct = r.headers.get('Content-Type', '').lower()
348
-
349
- if 'text/html' in ct:
350
- continue
351
-
352
- # 检测 SQL 错误
353
- text_lower = r.text.lower()
354
- sql_patterns = ['sql syntax', 'sql error', 'mysql', 'oracle',
355
- 'sqlite', 'sqlstate', 'postgresql']
356
- if any(p in text_lower for p in sql_patterns):
357
- self.vulnerabilities.append({
358
- 'type': 'SQL Injection',
359
- 'severity': 'CRITICAL',
360
- 'endpoint': path,
361
- })
362
- print(f" [!] {path}: SQL注入")
363
-
364
- except:
365
- pass
366
-
367
- print(f" 发现漏洞: {len(self.vulnerabilities)}")
368
-
369
- def _report_nginx_fallback(self):
370
- """报告 nginx fallback 问题"""
371
- self.vulnerabilities.append({
372
- 'type': 'Backend API Unreachable / nginx fallback',
373
- 'severity': 'HIGH',
374
- 'endpoint': 'Multiple paths',
375
- 'evidence': f'{len(self.parent_paths)} paths return HTML (nginx fallback)'
376
- })
377
- print(f" 添加问题: nginx fallback")
378
-
379
- def _cloud_storage_test(self):
380
- """云存储测试"""
381
- tester = CloudStorageTester(self.target)
382
- tester.session = self.session
383
- findings, storage_url = tester.full_test(self.target)
384
-
385
- print(f" 云存储: {storage_url}")
386
- print(f" 发现: {len(findings)}")
387
-
388
- self.cloud_findings = findings
389
-
390
- def _generate_report(self):
391
- """生成报告"""
392
- total_endpoints = len(self.static_endpoints) + len(self.dynamic_endpoints)
393
-
394
- print("\n" + "=" * 50)
395
- print(" 测试完成")
396
- print("=" * 50)
397
- print(f" 站点类型: {self.site_type}")
398
- print(f" 静态端点: {len(self.static_endpoints)}")
399
- print(f" 动态端点: {len(self.dynamic_endpoints)}")
400
- print(f" Hook 端点: {len(self.hooked_endpoints)}")
401
- print(f" JSON API: {sum(1 for p in self.parent_paths.values() if p.get('is_api'))}")
402
- print(f" 漏洞: {len(self.vulnerabilities)}")
403
- print(f" 云存储: {len(self.cloud_findings)}")
404
-
405
- def _get_result(self):
406
- """获取结果"""
407
- return {
408
- 'target': self.target,
409
- 'site_type': self.site_type,
410
- 'endpoints': {
411
- 'static': len(self.static_endpoints),
412
- 'dynamic': len(self.dynamic_endpoints),
413
- 'hooked': len(self.hooked_endpoints),
414
- 'parent_paths': len(self.parent_paths),
415
- 'json_api': sum(1 for p in self.parent_paths.values() if p.get('is_api')),
416
- },
417
- 'vulnerabilities': self.vulnerabilities,
418
- 'cloud_findings': self.cloud_findings,
419
- 'api_prefix': self.api_prefix,
420
- }
421
-
422
-
423
- if __name__ == "__main__":
424
- import sys
425
-
426
- if len(sys.argv) > 1:
427
- target = sys.argv[1]
428
- else:
429
- target = "http://58.216.151.148:8972/do/mh/jtmhindex"
430
-
431
- executor = SKILLExecutor(target)
432
- result = executor.run()
433
-
434
- print("\n\n结果:")
435
- print(result)