pentesting 0.43.0 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +349 -321
- package/dist/prompts/ctf-mode.md +1 -1
- package/dist/prompts/recon.md +3 -3
- package/dist/prompts/strategist-system.md +254 -22
- package/dist/prompts/strategy.md +8 -2
- package/dist/prompts/techniques/lateral.md +1 -1
- package/dist/prompts/techniques/network-svc.md +3 -3
- package/dist/prompts/vuln.md +2 -2
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -10,7 +10,6 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
10
10
|
import { render } from "ink";
|
|
11
11
|
import { Command } from "commander";
|
|
12
12
|
import chalk from "chalk";
|
|
13
|
-
import gradient from "gradient-string";
|
|
14
13
|
|
|
15
14
|
// src/platform/tui/app.tsx
|
|
16
15
|
import { useState as useState4, useCallback as useCallback4, useEffect as useEffect4, useRef as useRef4 } from "react";
|
|
@@ -307,14 +306,12 @@ var ORPHAN_PROCESS_NAMES = [
|
|
|
307
306
|
"dnsspoof",
|
|
308
307
|
"tcpdump",
|
|
309
308
|
"tshark",
|
|
310
|
-
"socat"
|
|
311
|
-
"nc",
|
|
312
|
-
"python"
|
|
309
|
+
"socat"
|
|
313
310
|
];
|
|
314
311
|
|
|
315
312
|
// src/shared/constants/agent.ts
|
|
316
313
|
var APP_NAME = "Pentest AI";
|
|
317
|
-
var APP_VERSION = "0.
|
|
314
|
+
var APP_VERSION = "0.44.0";
|
|
318
315
|
var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
|
|
319
316
|
var LLM_ROLES = {
|
|
320
317
|
SYSTEM: "system",
|
|
@@ -342,6 +339,146 @@ var SENSITIVE_INPUT_TYPES = [
|
|
|
342
339
|
INPUT_TYPES.CREDENTIAL
|
|
343
340
|
];
|
|
344
341
|
|
|
342
|
+
// src/shared/utils/time-strategy.ts
|
|
343
|
+
var PHASE_RATIOS = {
|
|
344
|
+
/** Sprint ends at 25% of total time */
|
|
345
|
+
SPRINT_END: 0.25,
|
|
346
|
+
/** Exploit phase ends at 50% of total time */
|
|
347
|
+
EXPLOIT_END: 0.5,
|
|
348
|
+
/** Creative phase ends at 75% of total time */
|
|
349
|
+
CREATIVE_END: 0.75
|
|
350
|
+
// Harvest: 75%-100%
|
|
351
|
+
};
|
|
352
|
+
var DEFAULT_DURATION_SEC = 86400;
|
|
353
|
+
var MIN_DURATION_SEC = 300;
|
|
354
|
+
var MAX_DURATION_SEC = 604800;
|
|
355
|
+
var MS_PER_SEC = 1e3;
|
|
356
|
+
function getSessionDurationMs() {
|
|
357
|
+
const envValue = process.env.PENTEST_DURATION;
|
|
358
|
+
if (envValue) {
|
|
359
|
+
const parsed = parseInt(envValue, 10);
|
|
360
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
361
|
+
const clamped = Math.max(MIN_DURATION_SEC, Math.min(MAX_DURATION_SEC, parsed));
|
|
362
|
+
return clamped * MS_PER_SEC;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return DEFAULT_DURATION_SEC * MS_PER_SEC;
|
|
366
|
+
}
|
|
367
|
+
function computeDeadline(startedAt) {
|
|
368
|
+
return startedAt + getSessionDurationMs();
|
|
369
|
+
}
|
|
370
|
+
function formatDuration(totalSec) {
|
|
371
|
+
if (totalSec <= 0) return "0s";
|
|
372
|
+
const h = Math.floor(totalSec / 3600);
|
|
373
|
+
const m = Math.floor(totalSec % 3600 / 60);
|
|
374
|
+
const s = Math.floor(totalSec % 60);
|
|
375
|
+
if (h > 0 && m > 0) return `${h}h${m}m`;
|
|
376
|
+
if (h > 0) return `${h}h`;
|
|
377
|
+
if (m > 0 && s > 0) return `${m}m${s}s`;
|
|
378
|
+
if (m > 0) return `${m}m`;
|
|
379
|
+
return `${s}s`;
|
|
380
|
+
}
|
|
381
|
+
function getTimeAdaptiveStrategy(elapsedMs, deadlineMs) {
|
|
382
|
+
let totalMs;
|
|
383
|
+
let remainingMs;
|
|
384
|
+
if (deadlineMs > 0) {
|
|
385
|
+
remainingMs = Math.max(0, deadlineMs - Date.now());
|
|
386
|
+
totalMs = elapsedMs + remainingMs;
|
|
387
|
+
} else {
|
|
388
|
+
totalMs = getSessionDurationMs();
|
|
389
|
+
remainingMs = Math.max(0, totalMs - elapsedMs);
|
|
390
|
+
}
|
|
391
|
+
if (totalMs <= 0) totalMs = 1;
|
|
392
|
+
const progress = Math.min(1, elapsedMs / totalMs);
|
|
393
|
+
const remainingSec = Math.floor(remainingMs / MS_PER_SEC);
|
|
394
|
+
const totalDurationSec = Math.floor(totalMs / MS_PER_SEC);
|
|
395
|
+
const elapsedStr = formatDuration(Math.floor(elapsedMs / MS_PER_SEC));
|
|
396
|
+
const remainStr = formatDuration(remainingSec);
|
|
397
|
+
const totalStr = formatDuration(totalDurationSec);
|
|
398
|
+
const pctStr = `${Math.floor(progress * 100)}%`;
|
|
399
|
+
if (progress >= PHASE_RATIOS.CREATIVE_END) {
|
|
400
|
+
return {
|
|
401
|
+
phase: "harvest",
|
|
402
|
+
label: "HARVEST",
|
|
403
|
+
urgency: "critical",
|
|
404
|
+
progress,
|
|
405
|
+
totalDurationSec,
|
|
406
|
+
remainingSec,
|
|
407
|
+
directive: [
|
|
408
|
+
`\u{1F3C1} HARVEST MODE [${pctStr} elapsed, ${remainStr} of ${totalStr} remaining]:`,
|
|
409
|
+
"- STOP exploring new attack vectors. Exploit what you HAVE.",
|
|
410
|
+
"- Submit ALL discovered flags immediately",
|
|
411
|
+
"- Check obvious flag locations: /root/flag.txt, user.txt, env vars, DB tables",
|
|
412
|
+
"- Re-check previously accessed systems for missed flags/proof",
|
|
413
|
+
"- Collect and record ALL evidence and proof files",
|
|
414
|
+
"- Write final report with all findings",
|
|
415
|
+
"- Credential spray ALL discovered creds on ALL remaining services",
|
|
416
|
+
remainingSec <= 300 ? "- \u26A0\uFE0F FINAL 5 MINUTES \u2014 submit everything NOW, stop all scans" : "- Focus on highest-confidence paths only"
|
|
417
|
+
].join("\n")
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
if (progress >= PHASE_RATIOS.EXPLOIT_END) {
|
|
421
|
+
return {
|
|
422
|
+
phase: "creative",
|
|
423
|
+
label: "CREATIVE",
|
|
424
|
+
urgency: "high",
|
|
425
|
+
progress,
|
|
426
|
+
totalDurationSec,
|
|
427
|
+
remainingSec,
|
|
428
|
+
directive: [
|
|
429
|
+
`\u{1F52C} CREATIVE MODE [${pctStr} elapsed, ${remainStr} of ${totalStr} remaining]:`,
|
|
430
|
+
"- Try advanced techniques: chained exploits, custom tools, race conditions",
|
|
431
|
+
"- Binary analysis for SUID/custom binaries, kernel exploits for privesc",
|
|
432
|
+
"- Protocol-level attacks: SMB relay, Kerberoasting, ADCS abuse",
|
|
433
|
+
'- Search for latest bypasses: web_search("{defense} bypass {year}")',
|
|
434
|
+
"- If stuck >5min on any vector, SWITCH immediately",
|
|
435
|
+
"- Start preparing evidence collection for final phase",
|
|
436
|
+
"- If all targets are compromised \u2192 skip to harvest immediately"
|
|
437
|
+
].join("\n")
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
if (progress >= PHASE_RATIOS.SPRINT_END) {
|
|
441
|
+
return {
|
|
442
|
+
phase: "exploit",
|
|
443
|
+
label: "EXPLOIT",
|
|
444
|
+
urgency: "medium",
|
|
445
|
+
progress,
|
|
446
|
+
totalDurationSec,
|
|
447
|
+
remainingSec,
|
|
448
|
+
directive: [
|
|
449
|
+
`\u{1F3AF} EXPLOIT MODE [${pctStr} elapsed, ${remainStr} of ${totalStr} remaining]:`,
|
|
450
|
+
"- Concentrate on discovered vectors with highest success probability",
|
|
451
|
+
"- Run parallel exploitation attempts on multiple targets",
|
|
452
|
+
"- Search for CVE PoCs for every identified service+version",
|
|
453
|
+
"- Chain: credentials \u2192 spray everywhere, LFI \u2192 config \u2192 DB creds",
|
|
454
|
+
"- Keep background scans running for new targets",
|
|
455
|
+
"- Time-box each vector: 10min max then switch",
|
|
456
|
+
"- If all vectors exhausted early \u2192 move to creative techniques immediately"
|
|
457
|
+
].join("\n")
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
return {
|
|
461
|
+
phase: "sprint",
|
|
462
|
+
label: "SPRINT",
|
|
463
|
+
urgency: "low",
|
|
464
|
+
progress,
|
|
465
|
+
totalDurationSec,
|
|
466
|
+
remainingSec,
|
|
467
|
+
directive: [
|
|
468
|
+
`\u26A1 SPRINT MODE [${pctStr} elapsed, ${remainStr} of ${totalStr} remaining]:`,
|
|
469
|
+
"- RustScan first for fast port discovery \u2192 then nmap -Pn -sV -sC on found ports",
|
|
470
|
+
"- ALWAYS use nmap -Pn (no exceptions \u2014 firewalls block ICMP)",
|
|
471
|
+
"- Run ALL scans in parallel (rustscan, nmap UDP, web fuzzing, CVE search)",
|
|
472
|
+
"- Try default/weak credentials on every discovered service IMMEDIATELY",
|
|
473
|
+
"- Check for exposed files (.env, .git, backup.sql, phpinfo)",
|
|
474
|
+
"- Anonymous access: FTP, SMB null session, Redis no auth, MongoDB",
|
|
475
|
+
"- OSINT: web_search for target intel, shodan, github repos",
|
|
476
|
+
"- Goal: Maximum attack surface discovery + instant wins",
|
|
477
|
+
"- \u26A1 If recon completes early \u2192 ATTACK IMMEDIATELY, do not wait for this phase to end"
|
|
478
|
+
].join("\n")
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
345
482
|
// src/shared/utils/id.ts
|
|
346
483
|
var ID_DEFAULT_RADIX = 36;
|
|
347
484
|
var ID_DEFAULT_LENGTH = 6;
|
|
@@ -2027,7 +2164,7 @@ async function cleanupAllProcesses() {
|
|
|
2027
2164
|
backgroundProcesses.clear();
|
|
2028
2165
|
for (const name of ORPHAN_PROCESS_NAMES) {
|
|
2029
2166
|
try {
|
|
2030
|
-
execSync2(`pkill -
|
|
2167
|
+
execSync2(`pkill -x "${name}" 2>/dev/null || true`, { stdio: "ignore", timeout: SYSTEM_LIMITS.PROCESS_OP_TIMEOUT_MS });
|
|
2031
2168
|
} catch {
|
|
2032
2169
|
}
|
|
2033
2170
|
}
|
|
@@ -2652,6 +2789,22 @@ var AttackGraph = class {
|
|
|
2652
2789
|
if (nodeCount >= GRAPH_LIMITS.ASCII_MAX_NODES) break;
|
|
2653
2790
|
const sIcon = statusIcons[node.status] || "?";
|
|
2654
2791
|
const fail = node.status === NODE_STATUS.FAILED && node.failReason ? ` \u2014 ${node.failReason}` : "";
|
|
2792
|
+
let detail = "";
|
|
2793
|
+
if (type === NODE_TYPE.CREDENTIAL) {
|
|
2794
|
+
const source = node.data.source ? ` (from: ${node.data.source})` : "";
|
|
2795
|
+
detail = source;
|
|
2796
|
+
} else if (type === NODE_TYPE.VULNERABILITY) {
|
|
2797
|
+
const sev = node.data.severity ? ` [${String(node.data.severity).toUpperCase()}]` : "";
|
|
2798
|
+
const exploit = node.data.hasExploit ? " [EXPLOIT]" : "";
|
|
2799
|
+
const target = node.data.target ? ` \u2192 ${node.data.target}` : "";
|
|
2800
|
+
detail = `${sev}${exploit}${target}`;
|
|
2801
|
+
} else if (type === NODE_TYPE.ACCESS) {
|
|
2802
|
+
const via = node.data.via ? ` via ${node.data.via}` : "";
|
|
2803
|
+
detail = via;
|
|
2804
|
+
} else if (type === NODE_TYPE.SERVICE) {
|
|
2805
|
+
const ver = node.data.version ? ` (${node.data.version})` : "";
|
|
2806
|
+
detail = ver;
|
|
2807
|
+
}
|
|
2655
2808
|
const outEdges = this.edges.filter((e) => e.from === node.id);
|
|
2656
2809
|
const edgeStr = outEdges.length > 0 ? ` \u2192 ${outEdges.map((e) => {
|
|
2657
2810
|
const target = this.nodes.get(e.to);
|
|
@@ -2659,10 +2812,19 @@ var AttackGraph = class {
|
|
|
2659
2812
|
const eStatus = e.status === EDGE_STATUS.FAILED ? " \u2717" : e.status === EDGE_STATUS.SUCCEEDED ? " \u2713" : "";
|
|
2660
2813
|
return `${eName}${eStatus}`;
|
|
2661
2814
|
}).join(", ")}` : "";
|
|
2662
|
-
lines.push(`\u2502 ${sIcon} ${node.label}${fail}${edgeStr}`);
|
|
2815
|
+
lines.push(`\u2502 ${sIcon} ${node.label}${detail}${fail}${edgeStr}`);
|
|
2663
2816
|
nodeCount++;
|
|
2664
2817
|
}
|
|
2665
2818
|
}
|
|
2819
|
+
const succeededNodes = Array.from(this.nodes.values()).filter((n) => n.status === NODE_STATUS.SUCCEEDED);
|
|
2820
|
+
if (succeededNodes.length > 0) {
|
|
2821
|
+
lines.push(`\u2502`);
|
|
2822
|
+
lines.push(`\u251C\u2500\u2500\u2500 Exploited \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524`);
|
|
2823
|
+
for (const n of succeededNodes) {
|
|
2824
|
+
const via = n.data.via ? ` via ${n.data.via}` : "";
|
|
2825
|
+
lines.push(`\u2502 \u25CF ${n.label}${via}`);
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2666
2828
|
const stats = this.getStats();
|
|
2667
2829
|
lines.push(`\u2502`);
|
|
2668
2830
|
lines.push(`\u251C\u2500\u2500\u2500 Summary \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524`);
|
|
@@ -3183,6 +3345,7 @@ var SharedState = class {
|
|
|
3183
3345
|
// ─── Improvement #7: Dynamic Technique Library ────────────────
|
|
3184
3346
|
dynamicTechniques = new DynamicTechniqueLibrary();
|
|
3185
3347
|
constructor() {
|
|
3348
|
+
const now = Date.now();
|
|
3186
3349
|
this.data = {
|
|
3187
3350
|
engagement: null,
|
|
3188
3351
|
targets: /* @__PURE__ */ new Map(),
|
|
@@ -3196,8 +3359,10 @@ var SharedState = class {
|
|
|
3196
3359
|
ctfMode: true,
|
|
3197
3360
|
// CTF mode ON by default
|
|
3198
3361
|
flags: [],
|
|
3199
|
-
startedAt:
|
|
3200
|
-
|
|
3362
|
+
startedAt: now,
|
|
3363
|
+
// Auto-configure from PENTEST_DURATION env (seconds).
|
|
3364
|
+
// Defaults to 24h if not set. Can be overridden via setDeadline().
|
|
3365
|
+
deadlineAt: computeDeadline(now),
|
|
3201
3366
|
challengeAnalysis: null
|
|
3202
3367
|
};
|
|
3203
3368
|
}
|
|
@@ -3206,6 +3371,7 @@ var SharedState = class {
|
|
|
3206
3371
|
* Used by /clear command to start a fresh session without recreating the agent.
|
|
3207
3372
|
*/
|
|
3208
3373
|
reset() {
|
|
3374
|
+
const now = Date.now();
|
|
3209
3375
|
this.data = {
|
|
3210
3376
|
engagement: null,
|
|
3211
3377
|
targets: /* @__PURE__ */ new Map(),
|
|
@@ -3218,8 +3384,8 @@ var SharedState = class {
|
|
|
3218
3384
|
missionChecklist: [],
|
|
3219
3385
|
ctfMode: true,
|
|
3220
3386
|
flags: [],
|
|
3221
|
-
startedAt:
|
|
3222
|
-
deadlineAt:
|
|
3387
|
+
startedAt: now,
|
|
3388
|
+
deadlineAt: computeDeadline(now),
|
|
3223
3389
|
challengeAnalysis: null
|
|
3224
3390
|
};
|
|
3225
3391
|
this.attackGraph.reset();
|
|
@@ -3404,24 +3570,28 @@ var SharedState = class {
|
|
|
3404
3570
|
if (this.data.deadlineAt === 0) return 0;
|
|
3405
3571
|
return Math.max(0, this.data.deadlineAt - Date.now());
|
|
3406
3572
|
}
|
|
3407
|
-
/** Get time status string for prompt injection */
|
|
3573
|
+
/** Get time status string for prompt injection (ratio-based, aligned with PHASE_RATIOS) */
|
|
3408
3574
|
getTimeStatus() {
|
|
3409
3575
|
const elapsed = this.getElapsedMs();
|
|
3410
3576
|
const mins = Math.floor(elapsed / 6e4);
|
|
3411
3577
|
let status = `\u23F1 Elapsed: ${mins}min`;
|
|
3412
3578
|
if (this.data.deadlineAt > 0) {
|
|
3413
3579
|
const remainingMs = this.getRemainingMs();
|
|
3580
|
+
const totalMs = elapsed + remainingMs;
|
|
3581
|
+
const progress = totalMs > 0 ? elapsed / totalMs : 1;
|
|
3414
3582
|
const remainingMins = Math.floor(remainingMs / 6e4);
|
|
3415
|
-
if (
|
|
3583
|
+
if (remainingMs <= 0) {
|
|
3416
3584
|
status += " | \u26A0\uFE0F TIME IS UP \u2014 submit any flags you have NOW";
|
|
3417
|
-
} else if (
|
|
3585
|
+
} else if (progress >= 0.95) {
|
|
3418
3586
|
status += ` | \u{1F534} ${remainingMins}min LEFT \u2014 FINAL PUSH: submit flags, check obvious locations, env vars, DBs`;
|
|
3419
|
-
} else if (
|
|
3420
|
-
status += ` | \u{1F7E1} ${remainingMins}min LEFT \u2014 wrap up
|
|
3421
|
-
} else if (
|
|
3422
|
-
status += ` | \u{1F7E0} ${remainingMins}min LEFT \u2014
|
|
3587
|
+
} else if (progress >= 0.75) {
|
|
3588
|
+
status += ` | \u{1F7E1} ${remainingMins}min LEFT \u2014 HARVEST: wrap up, collect evidence, submit flags`;
|
|
3589
|
+
} else if (progress >= 0.5) {
|
|
3590
|
+
status += ` | \u{1F7E0} ${remainingMins}min LEFT \u2014 CREATIVE: advanced techniques, switch if stuck`;
|
|
3591
|
+
} else if (progress >= 0.25) {
|
|
3592
|
+
status += ` | \u{1F535} ${remainingMins}min LEFT \u2014 EXPLOIT: focus on discovered vectors`;
|
|
3423
3593
|
} else {
|
|
3424
|
-
status += ` | \u{1F7E2} ${remainingMins}min remaining`;
|
|
3594
|
+
status += ` | \u{1F7E2} ${remainingMins}min remaining \u2014 SPRINT: recon + quick wins`;
|
|
3425
3595
|
}
|
|
3426
3596
|
}
|
|
3427
3597
|
return status;
|
|
@@ -4912,26 +5082,31 @@ Detail: ${detail}
|
|
|
4912
5082
|
},
|
|
4913
5083
|
{
|
|
4914
5084
|
name: TOOL_NAMES.ADD_FINDING,
|
|
4915
|
-
description:
|
|
5085
|
+
description: `Add a security finding with full details.
|
|
5086
|
+
ALWAYS provide: description (HOW you exploited it, step-by-step), evidence (actual command output proving success), and attackPattern (MITRE ATT&CK tactic).
|
|
5087
|
+
Findings without evidence are marked as UNVERIFIED and have low credibility.`,
|
|
4916
5088
|
parameters: {
|
|
4917
|
-
title: { type: "string", description:
|
|
5089
|
+
title: { type: "string", description: 'Concise finding title (e.g., "Path Traversal via /download endpoint")' },
|
|
4918
5090
|
severity: { type: "string", description: "Severity: critical, high, medium, low, info" },
|
|
4919
|
-
affected: { type: "array", items: { type: "string" }, description:
|
|
5091
|
+
affected: { type: "array", items: { type: "string" }, description: 'Affected host:port or URLs (e.g., ["ctf.example.com:443/download"])' },
|
|
5092
|
+
description: { type: "string", description: "Detailed description: what the vulnerability is, how you exploited it step-by-step, what access it gives, and the impact. Include credentials found, methods used, and exploitation chain." },
|
|
5093
|
+
evidence: { type: "array", items: { type: "string" }, description: 'Actual command outputs proving the finding (e.g., ["curl output showing /etc/passwd", "uid=0(root) gid=0(root)"]). Copy real output here.' },
|
|
4920
5094
|
attackPattern: { type: "string", description: "MITRE ATT&CK tactic: initial_access, execution, persistence, privilege_escalation, defense_evasion, credential_access, discovery, lateral_movement, collection, exfiltration, command_and_control, impact" }
|
|
4921
5095
|
},
|
|
4922
|
-
required: ["title", "severity"],
|
|
5096
|
+
required: ["title", "severity", "description", "evidence"],
|
|
4923
5097
|
execute: async (p) => {
|
|
4924
5098
|
const evidence = p.evidence || [];
|
|
4925
5099
|
const title = p.title;
|
|
4926
5100
|
const severity = p.severity;
|
|
4927
5101
|
const affected = p.affected || [];
|
|
5102
|
+
const description = p.description || "";
|
|
4928
5103
|
const validation = validateFinding(evidence, severity);
|
|
4929
5104
|
state.addFinding({
|
|
4930
5105
|
id: generateId(AGENT_LIMITS.ID_RADIX, AGENT_LIMITS.ID_LENGTH),
|
|
4931
5106
|
title,
|
|
4932
5107
|
severity,
|
|
4933
5108
|
affected,
|
|
4934
|
-
description
|
|
5109
|
+
description,
|
|
4935
5110
|
evidence,
|
|
4936
5111
|
isVerified: validation.isVerified,
|
|
4937
5112
|
remediation: "",
|
|
@@ -8686,6 +8861,11 @@ var NETWORK_ERROR_CODES = {
|
|
|
8686
8861
|
ENOTFOUND: "ENOTFOUND",
|
|
8687
8862
|
CONNECT_TIMEOUT: "UND_ERR_CONNECT_TIMEOUT"
|
|
8688
8863
|
};
|
|
8864
|
+
var TRANSIENT_NETWORK_ERRORS = [
|
|
8865
|
+
NETWORK_ERROR_CODES.ECONNRESET,
|
|
8866
|
+
NETWORK_ERROR_CODES.ETIMEDOUT,
|
|
8867
|
+
NETWORK_ERROR_CODES.ENOTFOUND
|
|
8868
|
+
];
|
|
8689
8869
|
var LLMError = class extends Error {
|
|
8690
8870
|
/** Structured error information */
|
|
8691
8871
|
errorInfo;
|
|
@@ -8696,8 +8876,11 @@ var LLMError = class extends Error {
|
|
|
8696
8876
|
}
|
|
8697
8877
|
};
|
|
8698
8878
|
function classifyError(error) {
|
|
8879
|
+
if (error === null || error === void 0) {
|
|
8880
|
+
return { type: LLM_ERROR_TYPES.UNKNOWN, message: String(error), isRetryable: false, suggestedAction: "Analyze error" };
|
|
8881
|
+
}
|
|
8699
8882
|
const e = error;
|
|
8700
|
-
const statusCode = e
|
|
8883
|
+
const statusCode = e?.status || e?.statusCode;
|
|
8701
8884
|
const errorMessage = e?.error?.error?.message || e?.error?.message || e?.message || String(error);
|
|
8702
8885
|
if (statusCode === HTTP_STATUS.RATE_LIMIT || errorMessage.toLowerCase().includes("rate limit")) {
|
|
8703
8886
|
return { type: LLM_ERROR_TYPES.RATE_LIMIT, message: errorMessage, statusCode, isRetryable: true, suggestedAction: "Wait and retry" };
|
|
@@ -8708,7 +8891,7 @@ function classifyError(error) {
|
|
|
8708
8891
|
if (statusCode === HTTP_STATUS.BAD_REQUEST) {
|
|
8709
8892
|
return { type: LLM_ERROR_TYPES.INVALID_REQUEST, message: errorMessage, statusCode, isRetryable: false, suggestedAction: "Modify request" };
|
|
8710
8893
|
}
|
|
8711
|
-
if (e.code
|
|
8894
|
+
if (e.code && TRANSIENT_NETWORK_ERRORS.includes(e.code)) {
|
|
8712
8895
|
return { type: LLM_ERROR_TYPES.NETWORK_ERROR, message: errorMessage, isRetryable: true, suggestedAction: "Check network" };
|
|
8713
8896
|
}
|
|
8714
8897
|
if (errorMessage.toLowerCase().includes("timeout") || e.code === NETWORK_ERROR_CODES.CONNECT_TIMEOUT) {
|
|
@@ -10317,100 +10500,6 @@ var INITIAL_TASKS = {
|
|
|
10317
10500
|
RECON: "Initial reconnaissance and target discovery"
|
|
10318
10501
|
};
|
|
10319
10502
|
|
|
10320
|
-
// src/shared/utils/time-strategy.ts
|
|
10321
|
-
var TIME_CONSTANTS = {
|
|
10322
|
-
/** Milliseconds per minute */
|
|
10323
|
-
MS_PER_MINUTE: 6e4,
|
|
10324
|
-
/** Minutes threshold for sprint-to-exploit switch (no deadline mode) */
|
|
10325
|
-
SPRINT_MINUTES: 10,
|
|
10326
|
-
/** Deadline percentage thresholds for phase transitions */
|
|
10327
|
-
PHASE_SPRINT: 0.25,
|
|
10328
|
-
PHASE_EXPLOIT: 0.5,
|
|
10329
|
-
PHASE_CREATIVE: 0.75
|
|
10330
|
-
};
|
|
10331
|
-
function getTimeAdaptiveStrategy(elapsedMs, deadlineMs) {
|
|
10332
|
-
if (deadlineMs === 0) {
|
|
10333
|
-
const mins = Math.floor(elapsedMs / TIME_CONSTANTS.MS_PER_MINUTE);
|
|
10334
|
-
if (mins < TIME_CONSTANTS.SPRINT_MINUTES) {
|
|
10335
|
-
return {
|
|
10336
|
-
phase: "sprint",
|
|
10337
|
-
label: "SPRINT",
|
|
10338
|
-
urgency: "low",
|
|
10339
|
-
directive: `\u26A1 SPRINT MODE (${mins}min elapsed): Parallel reconnaissance. Full port scan + service enumeration + default credentials. Attack immediately on any finding.`
|
|
10340
|
-
};
|
|
10341
|
-
}
|
|
10342
|
-
return {
|
|
10343
|
-
phase: "exploit",
|
|
10344
|
-
label: "EXPLOIT",
|
|
10345
|
-
urgency: "low",
|
|
10346
|
-
directive: `\u{1F3AF} EXPLOIT MODE (${mins}min elapsed): Focus on discovered vectors. Chain findings. Build custom tools if needed.`
|
|
10347
|
-
};
|
|
10348
|
-
}
|
|
10349
|
-
const totalMs = deadlineMs - (deadlineMs > Date.now() ? Date.now() - elapsedMs : 0);
|
|
10350
|
-
const remainingMs = Math.max(0, deadlineMs - Date.now());
|
|
10351
|
-
const pct = totalMs > 0 ? 1 - remainingMs / totalMs : 1;
|
|
10352
|
-
const remainingMins = Math.floor(remainingMs / TIME_CONSTANTS.MS_PER_MINUTE);
|
|
10353
|
-
if (pct < TIME_CONSTANTS.PHASE_SPRINT) {
|
|
10354
|
-
return {
|
|
10355
|
-
phase: "sprint",
|
|
10356
|
-
label: "SPRINT",
|
|
10357
|
-
urgency: "low",
|
|
10358
|
-
directive: [
|
|
10359
|
-
`\u26A1 SPRINT MODE (${remainingMins}min remaining):`,
|
|
10360
|
-
"- Run ALL scans in parallel (nmap TCP/UDP, web fuzzing, CVE search)",
|
|
10361
|
-
"- Try default/weak credentials on every discovered service IMMEDIATELY",
|
|
10362
|
-
"- Check for exposed files (.env, .git, backup.sql, phpinfo)",
|
|
10363
|
-
"- Anonymous access: FTP, SMB null session, Redis no auth, MongoDB",
|
|
10364
|
-
"- Goal: Maximum attack surface discovery + instant wins"
|
|
10365
|
-
].join("\n")
|
|
10366
|
-
};
|
|
10367
|
-
}
|
|
10368
|
-
if (pct < TIME_CONSTANTS.PHASE_EXPLOIT) {
|
|
10369
|
-
return {
|
|
10370
|
-
phase: "exploit",
|
|
10371
|
-
label: "EXPLOIT",
|
|
10372
|
-
urgency: "medium",
|
|
10373
|
-
directive: [
|
|
10374
|
-
`\u{1F3AF} EXPLOIT MODE (${remainingMins}min remaining):`,
|
|
10375
|
-
"- Concentrate on discovered vectors with highest success probability",
|
|
10376
|
-
"- Run parallel exploitation attempts on multiple targets",
|
|
10377
|
-
"- Search for CVE PoCs for every identified service+version",
|
|
10378
|
-
"- Chain: credentials \u2192 spray everywhere, LFI \u2192 config \u2192 DB creds",
|
|
10379
|
-
"- Keep background scans running for new targets"
|
|
10380
|
-
].join("\n")
|
|
10381
|
-
};
|
|
10382
|
-
}
|
|
10383
|
-
if (pct < TIME_CONSTANTS.PHASE_CREATIVE) {
|
|
10384
|
-
return {
|
|
10385
|
-
phase: "creative",
|
|
10386
|
-
label: "CREATIVE",
|
|
10387
|
-
urgency: "high",
|
|
10388
|
-
directive: [
|
|
10389
|
-
`\u{1F52C} CREATIVE MODE (${remainingMins}min remaining):`,
|
|
10390
|
-
"- Try advanced techniques: chained exploits, custom tools, race conditions",
|
|
10391
|
-
"- Binary analysis for SUID/custom binaries, kernel exploits for privesc",
|
|
10392
|
-
"- Protocol-level attacks: SMB relay, Kerberoasting, ADCS abuse",
|
|
10393
|
-
'- Search for latest bypasses: web_search("{defense} bypass 2025")',
|
|
10394
|
-
"- If stuck >5min on any vector, SWITCH immediately"
|
|
10395
|
-
].join("\n")
|
|
10396
|
-
};
|
|
10397
|
-
}
|
|
10398
|
-
return {
|
|
10399
|
-
phase: "harvest",
|
|
10400
|
-
label: "HARVEST",
|
|
10401
|
-
urgency: "critical",
|
|
10402
|
-
directive: [
|
|
10403
|
-
`\u{1F3C1} HARVEST MODE (${remainingMins}min remaining \u2014 FINAL PUSH):`,
|
|
10404
|
-
"- STOP exploring new vectors. Focus on what you HAVE.",
|
|
10405
|
-
"- Submit ALL discovered flags immediately",
|
|
10406
|
-
"- Check obvious flag locations: /root/flag.txt, env vars, DB tables",
|
|
10407
|
-
"- Re-check previously accessed systems for missed flags",
|
|
10408
|
-
"- Collect and record ALL evidence and proof files",
|
|
10409
|
-
"- Write final report with all findings"
|
|
10410
|
-
].join("\n")
|
|
10411
|
-
};
|
|
10412
|
-
}
|
|
10413
|
-
|
|
10414
10503
|
// src/shared/constants/service-ports.ts
|
|
10415
10504
|
var SERVICE_PORTS = {
|
|
10416
10505
|
SSH: 22,
|
|
@@ -10960,12 +11049,13 @@ var STRATEGIST_LIMITS = {
|
|
|
10960
11049
|
* Full state can be 20K+; Strategist needs summary, not everything. */
|
|
10961
11050
|
MAX_INPUT_CHARS: 15e3,
|
|
10962
11051
|
/** Maximum characters for the Strategist's response.
|
|
10963
|
-
* WHY: Directives should be terse and actionable (~
|
|
10964
|
-
*
|
|
10965
|
-
MAX_OUTPUT_CHARS:
|
|
11052
|
+
* WHY: Directives should be terse and actionable (~800-1500 tokens).
|
|
11053
|
+
* Enhanced format includes SITUATION, priorities, EXHAUSTED, and SEARCH ORDERS. */
|
|
11054
|
+
MAX_OUTPUT_CHARS: 5e3,
|
|
10966
11055
|
/** Maximum lines in the directive output.
|
|
10967
|
-
* WHY: Forces concise, prioritized directives
|
|
10968
|
-
|
|
11056
|
+
* WHY: Forces concise, prioritized directives while allowing
|
|
11057
|
+
* structured format (priorities + exhausted + search orders). */
|
|
11058
|
+
MAX_DIRECTIVE_LINES: 60
|
|
10969
11059
|
};
|
|
10970
11060
|
|
|
10971
11061
|
// src/agents/strategist.ts
|
|
@@ -11134,11 +11224,14 @@ NOTE: This directive is from ${age}min ago (Strategist call failed this turn). V
|
|
|
11134
11224
|
this.totalCalls = 0;
|
|
11135
11225
|
}
|
|
11136
11226
|
};
|
|
11137
|
-
var FALLBACK_SYSTEM_PROMPT = `You are
|
|
11138
|
-
Analyze the
|
|
11139
|
-
|
|
11140
|
-
|
|
11141
|
-
|
|
11227
|
+
var FALLBACK_SYSTEM_PROMPT = `You are an elite autonomous penetration testing STRATEGIST \u2014 a red team tactical commander.
|
|
11228
|
+
Analyze the engagement state and issue precise attack orders for the execution agent.
|
|
11229
|
+
Format: SITUATION line, numbered PRIORITY items with ACTION/SEARCH/SUCCESS/FALLBACK/CHAIN fields, EXHAUSTED list, and SEARCH ORDERS.
|
|
11230
|
+
Be surgically specific: name exact tools, commands, parameters, and wordlists. The agent copy-pastes your commands.
|
|
11231
|
+
Include mandatory web_search directives for every unknown service/version.
|
|
11232
|
+
Detect stalls (repeated failures, no progress) and force completely different attack vectors.
|
|
11233
|
+
Chain every finding: "If X works \u2192 immediately do Y \u2192 which enables Z."
|
|
11234
|
+
Maximum 50 lines. Zero preamble. Direct imperatives only. Never repeat failed approaches.`;
|
|
11142
11235
|
|
|
11143
11236
|
// src/agents/main-agent.ts
|
|
11144
11237
|
var MainAgent = class extends CoreAgent {
|
|
@@ -11319,7 +11412,7 @@ var AgentFactory = class {
|
|
|
11319
11412
|
};
|
|
11320
11413
|
|
|
11321
11414
|
// src/platform/tui/utils/format.ts
|
|
11322
|
-
var
|
|
11415
|
+
var formatDuration2 = (ms) => {
|
|
11323
11416
|
const totalSec = ms / 1e3;
|
|
11324
11417
|
if (totalSec < 60) return `${totalSec.toFixed(1)}s`;
|
|
11325
11418
|
const minutes = Math.floor(totalSec / 60);
|
|
@@ -11333,7 +11426,7 @@ var formatTokens = (count) => {
|
|
|
11333
11426
|
};
|
|
11334
11427
|
var formatMeta = (ms, tokens) => {
|
|
11335
11428
|
const parts = [];
|
|
11336
|
-
if (ms > 0) parts.push(
|
|
11429
|
+
if (ms > 0) parts.push(formatDuration2(ms));
|
|
11337
11430
|
if (tokens > 0) parts.push(`\u2191 ${formatTokens(tokens)} tokens`);
|
|
11338
11431
|
return parts.length > 0 ? `(${parts.join(" \xB7 ")})` : "";
|
|
11339
11432
|
};
|
|
@@ -11367,135 +11460,59 @@ var formatInlineStatus = () => {
|
|
|
11367
11460
|
import { useState, useRef, useCallback } from "react";
|
|
11368
11461
|
|
|
11369
11462
|
// src/shared/constants/theme.ts
|
|
11463
|
+
var COLORS = {
|
|
11464
|
+
primary: "#e11d48",
|
|
11465
|
+
// Rose 600 - red team primary
|
|
11466
|
+
accent: "#fb923c",
|
|
11467
|
+
// Orange 400 - fire accent
|
|
11468
|
+
secondary: "#94a3b8",
|
|
11469
|
+
// Slate - secondary/muted
|
|
11470
|
+
white: "#f8fafc",
|
|
11471
|
+
// Main text
|
|
11472
|
+
red: "#ff4500",
|
|
11473
|
+
// OrangeRed - Error/Critical (distinct from rose primary)
|
|
11474
|
+
yellow: "#facc15"
|
|
11475
|
+
// Yellow 400 - Warning/Pending (pure yellow)
|
|
11476
|
+
};
|
|
11370
11477
|
var THEME = {
|
|
11371
|
-
|
|
11478
|
+
...COLORS,
|
|
11372
11479
|
bg: {
|
|
11373
11480
|
primary: "#050505",
|
|
11374
|
-
// Deepest black
|
|
11375
|
-
secondary: "#0a0c10",
|
|
11376
|
-
// Dark void
|
|
11377
|
-
tertiary: "#0f172a",
|
|
11378
|
-
// Slate dark
|
|
11379
|
-
elevated: "#1e293b",
|
|
11380
|
-
// Bright slate
|
|
11381
11481
|
input: "#020617"
|
|
11382
|
-
// Midnight
|
|
11383
11482
|
},
|
|
11384
|
-
// Text colors
|
|
11385
11483
|
text: {
|
|
11386
|
-
primary:
|
|
11387
|
-
|
|
11388
|
-
|
|
11389
|
-
|
|
11390
|
-
|
|
11391
|
-
// Lighter blue-gray
|
|
11392
|
-
accent: "#1d4ed8",
|
|
11393
|
-
// Blue 700 - deep blue
|
|
11394
|
-
highlight: "#ffffff"
|
|
11395
|
-
// Pure white
|
|
11484
|
+
primary: COLORS.white,
|
|
11485
|
+
secondary: COLORS.secondary,
|
|
11486
|
+
muted: "#64748b",
|
|
11487
|
+
accent: COLORS.accent
|
|
11488
|
+
// Using Emerald for "accented" text
|
|
11396
11489
|
},
|
|
11397
|
-
// Status colors (deep blue-focused)
|
|
11398
11490
|
status: {
|
|
11399
|
-
success:
|
|
11400
|
-
//
|
|
11401
|
-
warning:
|
|
11402
|
-
|
|
11403
|
-
|
|
11404
|
-
//
|
|
11405
|
-
info: "#1d4ed8",
|
|
11406
|
-
// Blue 700
|
|
11407
|
-
running: "#1e40af",
|
|
11408
|
-
// Blue 800 (AI activity)
|
|
11409
|
-
pending: "#64748b"
|
|
11410
|
-
// Slate
|
|
11411
|
-
},
|
|
11412
|
-
// Severity colors
|
|
11413
|
-
semantic: {
|
|
11414
|
-
critical: "#7f1d1d",
|
|
11415
|
-
// Dark red
|
|
11416
|
-
high: "#ef4444",
|
|
11417
|
-
// Red
|
|
11418
|
-
medium: "#f97316",
|
|
11419
|
-
// Orange
|
|
11420
|
-
low: "#eab308",
|
|
11421
|
-
// Yellow
|
|
11422
|
-
info: "#1d4ed8"
|
|
11423
|
-
// Blue 700
|
|
11491
|
+
success: COLORS.accent,
|
|
11492
|
+
// Success feels good in emerald
|
|
11493
|
+
warning: COLORS.yellow,
|
|
11494
|
+
error: COLORS.red,
|
|
11495
|
+
running: COLORS.primary
|
|
11496
|
+
// System operations in blue
|
|
11424
11497
|
},
|
|
11425
|
-
// Border colors
|
|
11426
11498
|
border: {
|
|
11427
11499
|
default: "#1e293b",
|
|
11428
|
-
focus:
|
|
11429
|
-
|
|
11430
|
-
error: "#ef4444",
|
|
11431
|
-
success: "#22c55e"
|
|
11500
|
+
focus: COLORS.primary,
|
|
11501
|
+
error: COLORS.red
|
|
11432
11502
|
},
|
|
11433
|
-
// Phase colors (deep blue-focused)
|
|
11434
|
-
phase: {
|
|
11435
|
-
recon: "#94a3b8",
|
|
11436
|
-
enum: "#1d4ed8",
|
|
11437
|
-
// Blue 700 (phase indicator)
|
|
11438
|
-
vuln: "#f59e0b",
|
|
11439
|
-
exploit: "#ef4444",
|
|
11440
|
-
privesc: "#8b5cf6",
|
|
11441
|
-
persist: "#22c55e",
|
|
11442
|
-
report: "#64748b"
|
|
11443
|
-
},
|
|
11444
|
-
// Accent colors (NO cyan/teal - pure blue palette)
|
|
11445
|
-
accent: {
|
|
11446
|
-
pink: "#f472b6",
|
|
11447
|
-
rose: "#fb7185",
|
|
11448
|
-
fuchsia: "#e879f9",
|
|
11449
|
-
purple: "#a78bfa",
|
|
11450
|
-
violet: "#8b5cf6",
|
|
11451
|
-
indigo: "#818cf8",
|
|
11452
|
-
blue: "#1d4ed8",
|
|
11453
|
-
// Blue 700 - primary accent
|
|
11454
|
-
emerald: "#34d399",
|
|
11455
|
-
green: "#4ade80",
|
|
11456
|
-
lime: "#a3e635",
|
|
11457
|
-
yellow: "#facc15",
|
|
11458
|
-
amber: "#fbbf24",
|
|
11459
|
-
orange: "#fb923c",
|
|
11460
|
-
red: "#f87171"
|
|
11461
|
-
},
|
|
11462
|
-
// Gradients (deep blue-focused)
|
|
11463
11503
|
gradient: {
|
|
11464
|
-
cyber: [
|
|
11465
|
-
|
|
11466
|
-
// Blue 500
|
|
11467
|
-
"#3584f4",
|
|
11468
|
-
"#2f86f2",
|
|
11469
|
-
"#2988f0",
|
|
11470
|
-
"#238aee",
|
|
11471
|
-
"#1d8cec",
|
|
11472
|
-
// Mid blue
|
|
11473
|
-
"#1d7ad8",
|
|
11474
|
-
"#1d78c6",
|
|
11475
|
-
"#1d76b4",
|
|
11476
|
-
"#1d74a2",
|
|
11477
|
-
"#1e40af"
|
|
11478
|
-
// Blue 800
|
|
11479
|
-
],
|
|
11480
|
-
danger: ["#ef4444", "#7f1d1d"],
|
|
11481
|
-
success: ["#22c55e", "#14532d"],
|
|
11482
|
-
gold: ["#f59e0b", "#78350f"],
|
|
11483
|
-
royal: ["#818cf8", "#312e81"]
|
|
11504
|
+
cyber: [COLORS.primary, "#f43f5e", "#fb923c"]
|
|
11505
|
+
// Red team fire gradient: rose → pink → amber
|
|
11484
11506
|
},
|
|
11485
|
-
|
|
11486
|
-
spinner: "#3b82f6",
|
|
11487
|
-
// Blue 500
|
|
11488
|
-
// Identity color (branded accent - deep blue)
|
|
11489
|
-
identity: "#1d4ed8"
|
|
11490
|
-
// Blue 700
|
|
11507
|
+
spinner: COLORS.primary
|
|
11491
11508
|
};
|
|
11492
11509
|
var ASCII_BANNER = `
|
|
11493
|
-
|
|
11494
|
-
|
|
11495
|
-
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
|
|
11510
|
+
\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
11511
|
+
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D
|
|
11512
|
+
\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557
|
|
11513
|
+
\u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551
|
|
11514
|
+
\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
|
|
11515
|
+
\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D
|
|
11499
11516
|
`;
|
|
11500
11517
|
var ICONS = {
|
|
11501
11518
|
// Status
|
|
@@ -11509,7 +11526,7 @@ var ICONS = {
|
|
|
11509
11526
|
target: "\u25C8",
|
|
11510
11527
|
// Diamond for target
|
|
11511
11528
|
scan: "\u25CE",
|
|
11512
|
-
exploit: "\
|
|
11529
|
+
exploit: "\u2607",
|
|
11513
11530
|
shell: "\u276F",
|
|
11514
11531
|
// Progress
|
|
11515
11532
|
pending: "\u25CB",
|
|
@@ -11521,9 +11538,9 @@ var ICONS = {
|
|
|
11521
11538
|
medium: "\u25C7",
|
|
11522
11539
|
low: "\u25E6",
|
|
11523
11540
|
// Security
|
|
11524
|
-
lock: "\
|
|
11525
|
-
unlock: "\
|
|
11526
|
-
key: "\
|
|
11541
|
+
lock: "\u22A1",
|
|
11542
|
+
unlock: "\u2B1A",
|
|
11543
|
+
key: "\u26B7",
|
|
11527
11544
|
flag: "\u2691",
|
|
11528
11545
|
// Simple flag
|
|
11529
11546
|
pwned: "\u25C8"
|
|
@@ -11580,7 +11597,7 @@ var MESSAGE_STYLES = {
|
|
|
11580
11597
|
error: THEME.status.error,
|
|
11581
11598
|
tool: THEME.status.running,
|
|
11582
11599
|
result: THEME.text.muted,
|
|
11583
|
-
status: THEME.
|
|
11600
|
+
status: THEME.primary
|
|
11584
11601
|
},
|
|
11585
11602
|
prefixes: {
|
|
11586
11603
|
user: "\u276F",
|
|
@@ -11641,21 +11658,9 @@ var useAgentState = () => {
|
|
|
11641
11658
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
11642
11659
|
const [currentStatus, setCurrentStatus] = useState("");
|
|
11643
11660
|
const [elapsedTime, setElapsedTime] = useState(0);
|
|
11644
|
-
const [retryState, setRetryState] = useState({
|
|
11645
|
-
isRetrying: false,
|
|
11646
|
-
attempt: 0,
|
|
11647
|
-
maxRetries: 0,
|
|
11648
|
-
delayMs: 0,
|
|
11649
|
-
error: "",
|
|
11650
|
-
countdown: 0
|
|
11651
|
-
});
|
|
11661
|
+
const [retryState, setRetryState] = useState({ status: "idle" });
|
|
11652
11662
|
const [currentTokens, setCurrentTokens] = useState(0);
|
|
11653
|
-
const [inputRequest, setInputRequest] = useState({
|
|
11654
|
-
isActive: false,
|
|
11655
|
-
prompt: "",
|
|
11656
|
-
isPassword: false,
|
|
11657
|
-
resolve: null
|
|
11658
|
-
});
|
|
11663
|
+
const [inputRequest, setInputRequest] = useState({ status: "inactive" });
|
|
11659
11664
|
const [stats, setStats] = useState({ phase: DEFAULTS.INIT_PHASE, targets: 0, findings: 0, todo: 0 });
|
|
11660
11665
|
const lastResponseMetaRef = useRef(null);
|
|
11661
11666
|
const startTimeRef = useRef(0);
|
|
@@ -11796,7 +11801,7 @@ var useAgentEvents = (agent, eventsRef, state) => {
|
|
|
11796
11801
|
const isPassword = /password|passphrase/i.test(p);
|
|
11797
11802
|
const inputType = /sudo/i.test(p) ? "sudo_password" : isPassword ? "password" : "text";
|
|
11798
11803
|
setInputRequest({
|
|
11799
|
-
|
|
11804
|
+
status: "active",
|
|
11800
11805
|
prompt: p.trim(),
|
|
11801
11806
|
isPassword,
|
|
11802
11807
|
inputType,
|
|
@@ -11810,7 +11815,7 @@ var useAgentEvents = (agent, eventsRef, state) => {
|
|
|
11810
11815
|
const isPassword = hiddenTypes.includes(request.type);
|
|
11811
11816
|
const displayPrompt = buildCredentialPrompt(request);
|
|
11812
11817
|
setInputRequest({
|
|
11813
|
-
|
|
11818
|
+
status: "active",
|
|
11814
11819
|
prompt: displayPrompt,
|
|
11815
11820
|
isPassword,
|
|
11816
11821
|
inputType: request.type,
|
|
@@ -11891,7 +11896,7 @@ function handleRetry(e, addMessage, setRetryState, retryCountdownRef, retryCount
|
|
|
11891
11896
|
const retryNum = retryCountRef.current;
|
|
11892
11897
|
addMessage("system", `\u27F3 Retry #${retryNum} \xB7 ${e.data.error} \xB7 waiting ${delaySec}s...`);
|
|
11893
11898
|
setRetryState({
|
|
11894
|
-
|
|
11899
|
+
status: "retrying",
|
|
11895
11900
|
attempt: retryNum,
|
|
11896
11901
|
maxRetries: e.data.maxRetries,
|
|
11897
11902
|
delayMs: e.data.delayMs,
|
|
@@ -11903,10 +11908,10 @@ function handleRetry(e, addMessage, setRetryState, retryCountdownRef, retryCount
|
|
|
11903
11908
|
retryCountdownRef.current = setInterval(() => {
|
|
11904
11909
|
remaining -= 1;
|
|
11905
11910
|
if (remaining <= 0) {
|
|
11906
|
-
setRetryState(
|
|
11911
|
+
setRetryState({ status: "idle" });
|
|
11907
11912
|
if (retryCountdownRef.current) clearInterval(retryCountdownRef.current);
|
|
11908
11913
|
} else {
|
|
11909
|
-
setRetryState((prev) =>
|
|
11914
|
+
setRetryState((prev) => prev.status === "retrying" ? { ...prev, countdown: remaining } : prev);
|
|
11910
11915
|
}
|
|
11911
11916
|
}, 1e3);
|
|
11912
11917
|
}
|
|
@@ -12001,9 +12006,9 @@ var useAgent = (shouldAutoApprove, target) => {
|
|
|
12001
12006
|
inputRequestRef.current = inputRequest;
|
|
12002
12007
|
const cancelInputRequest = useCallback2(() => {
|
|
12003
12008
|
const ir = inputRequestRef.current;
|
|
12004
|
-
if (ir.
|
|
12009
|
+
if (ir.status === "active") {
|
|
12005
12010
|
ir.resolve(null);
|
|
12006
|
-
setInputRequest({
|
|
12011
|
+
setInputRequest({ status: "inactive" });
|
|
12007
12012
|
addMessage("system", "Input cancelled");
|
|
12008
12013
|
}
|
|
12009
12014
|
}, [setInputRequest, addMessage]);
|
|
@@ -12045,7 +12050,7 @@ import { Box as Box2, Text as Text2, Static } from "ink";
|
|
|
12045
12050
|
// src/platform/tui/components/inline-status.tsx
|
|
12046
12051
|
import { Box, Text } from "ink";
|
|
12047
12052
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12048
|
-
function
|
|
12053
|
+
function formatDuration3(ms) {
|
|
12049
12054
|
const seconds = Math.floor(ms / 1e3);
|
|
12050
12055
|
if (seconds < 60) return `${seconds}s`;
|
|
12051
12056
|
const minutes = Math.floor(seconds / 60);
|
|
@@ -12057,13 +12062,13 @@ function formatDuration2(ms) {
|
|
|
12057
12062
|
}
|
|
12058
12063
|
function getRoleColor(role) {
|
|
12059
12064
|
const roleColors = {
|
|
12060
|
-
listener: THEME.
|
|
12061
|
-
active_shell: THEME.
|
|
12062
|
-
server: THEME.
|
|
12063
|
-
sniffer: THEME.
|
|
12064
|
-
spoofer: THEME.
|
|
12065
|
-
proxy: THEME.
|
|
12066
|
-
callback: THEME.
|
|
12065
|
+
listener: THEME.primary,
|
|
12066
|
+
active_shell: THEME.primary,
|
|
12067
|
+
server: THEME.secondary,
|
|
12068
|
+
sniffer: THEME.yellow,
|
|
12069
|
+
spoofer: THEME.yellow,
|
|
12070
|
+
proxy: THEME.primary,
|
|
12071
|
+
callback: THEME.primary,
|
|
12067
12072
|
background: THEME.text.muted
|
|
12068
12073
|
};
|
|
12069
12074
|
return roleColors[role] || THEME.text.secondary;
|
|
@@ -12087,7 +12092,7 @@ function StatusIndicator({ running, exitCode }) {
|
|
|
12087
12092
|
] });
|
|
12088
12093
|
}
|
|
12089
12094
|
function ProcessRow({ proc, compact }) {
|
|
12090
|
-
const duration =
|
|
12095
|
+
const duration = formatDuration3(proc.durationMs);
|
|
12091
12096
|
const port = proc.listeningPort ? `:${proc.listeningPort}` : "";
|
|
12092
12097
|
const purpose = proc.purpose || proc.description || "";
|
|
12093
12098
|
const truncatedPurpose = compact && purpose.length > TUI_DISPLAY_LIMITS.purposeMaxLength ? purpose.slice(0, TUI_DISPLAY_LIMITS.purposeTruncated) + "..." : purpose;
|
|
@@ -12260,7 +12265,7 @@ var StatusDisplay = memo3(({
|
|
|
12260
12265
|
};
|
|
12261
12266
|
const meta = formatMeta(elapsedTime * 1e3, currentTokens);
|
|
12262
12267
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 0, children: [
|
|
12263
|
-
retryState.
|
|
12268
|
+
retryState.status === "retrying" && /* @__PURE__ */ jsxs3(Box3, { marginBottom: 1, children: [
|
|
12264
12269
|
/* @__PURE__ */ jsx4(Text4, { color: THEME.status.warning, children: /* @__PURE__ */ jsx4(MusicSpinner, { color: THEME.status.warning }) }),
|
|
12265
12270
|
/* @__PURE__ */ jsxs3(Text4, { color: THEME.status.warning, children: [
|
|
12266
12271
|
" \u27F3 Retry #",
|
|
@@ -12270,13 +12275,13 @@ var StatusDisplay = memo3(({
|
|
|
12270
12275
|
" \xB7 ",
|
|
12271
12276
|
truncateError(retryState.error)
|
|
12272
12277
|
] }),
|
|
12273
|
-
/* @__PURE__ */ jsxs3(Text4, { color: THEME.
|
|
12278
|
+
/* @__PURE__ */ jsxs3(Text4, { color: THEME.primary, bold: true, children: [
|
|
12274
12279
|
" \xB7 ",
|
|
12275
12280
|
retryState.countdown,
|
|
12276
12281
|
"s"
|
|
12277
12282
|
] })
|
|
12278
12283
|
] }),
|
|
12279
|
-
isProcessing &&
|
|
12284
|
+
isProcessing && retryState.status !== "retrying" && /* @__PURE__ */ jsxs3(Box3, { marginBottom: 1, children: [
|
|
12280
12285
|
/* @__PURE__ */ jsx4(Text4, { color: THEME.spinner, children: /* @__PURE__ */ jsx4(MusicSpinner, { color: THEME.spinner }) }),
|
|
12281
12286
|
/* @__PURE__ */ jsxs3(Text4, { color: THEME.text.muted, children: [
|
|
12282
12287
|
" ",
|
|
@@ -12325,11 +12330,13 @@ var ChatInput = memo4(({
|
|
|
12325
12330
|
const onChangeRef = useRef3(onChange);
|
|
12326
12331
|
onChangeRef.current = onChange;
|
|
12327
12332
|
useInput(useCallback3((_input, key) => {
|
|
12328
|
-
if (inputRequestRef.current.
|
|
12333
|
+
if (inputRequestRef.current.status === "active") return;
|
|
12329
12334
|
if (key.tab && isSlashModeRef.current && !hasArgsRef.current && suggestionsRef.current.length > 0) {
|
|
12330
12335
|
const best = suggestionsRef.current[0];
|
|
12331
12336
|
const argsHint = best.args ? " " : "";
|
|
12332
|
-
|
|
12337
|
+
const completed = `/${best.name}${argsHint}`;
|
|
12338
|
+
onChangeRef.current("");
|
|
12339
|
+
setTimeout(() => onChangeRef.current(completed), 0);
|
|
12333
12340
|
}
|
|
12334
12341
|
}, []));
|
|
12335
12342
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
@@ -12343,7 +12350,7 @@ var ChatInput = memo4(({
|
|
|
12343
12350
|
marginBottom: 0,
|
|
12344
12351
|
children: suggestions.map((cmd, i) => {
|
|
12345
12352
|
const isFirst = i === 0;
|
|
12346
|
-
const nameColor = isFirst ? THEME.
|
|
12353
|
+
const nameColor = isFirst ? THEME.primary : THEME.text.secondary;
|
|
12347
12354
|
const aliasText = cmd.alias ? ` /${cmd.alias}` : "";
|
|
12348
12355
|
const argsText = cmd.args ? ` ${cmd.args}` : "";
|
|
12349
12356
|
return /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
@@ -12357,7 +12364,7 @@ var ChatInput = memo4(({
|
|
|
12357
12364
|
" \u2014 ",
|
|
12358
12365
|
cmd.description
|
|
12359
12366
|
] }),
|
|
12360
|
-
isFirst && /* @__PURE__ */ jsx5(Text5, { color: THEME.
|
|
12367
|
+
isFirst && /* @__PURE__ */ jsx5(Text5, { color: THEME.primary, children: " [Tab]" })
|
|
12361
12368
|
] }, cmd.name);
|
|
12362
12369
|
})
|
|
12363
12370
|
}
|
|
@@ -12366,9 +12373,9 @@ var ChatInput = memo4(({
|
|
|
12366
12373
|
Box4,
|
|
12367
12374
|
{
|
|
12368
12375
|
borderStyle: "single",
|
|
12369
|
-
borderColor: inputRequest.
|
|
12376
|
+
borderColor: inputRequest.status === "active" ? THEME.status.warning : THEME.border.default,
|
|
12370
12377
|
paddingX: 1,
|
|
12371
|
-
children: inputRequest.
|
|
12378
|
+
children: inputRequest.status === "active" ? /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
12372
12379
|
/* @__PURE__ */ jsx5(Text5, { color: THEME.status.warning, children: "[auth]" }),
|
|
12373
12380
|
/* @__PURE__ */ jsxs4(Text5, { color: THEME.text.muted, children: [
|
|
12374
12381
|
" ",
|
|
@@ -12427,7 +12434,7 @@ var Footer = memo5(({ phase, targets, findings, todo, elapsedTime, isProcessing
|
|
|
12427
12434
|
/* @__PURE__ */ jsxs5(Box5, { gap: 2, children: [
|
|
12428
12435
|
/* @__PURE__ */ jsxs5(Text6, { color: THEME.text.muted, children: [
|
|
12429
12436
|
"Phase: ",
|
|
12430
|
-
/* @__PURE__ */ jsx6(Text6, { color: THEME.
|
|
12437
|
+
/* @__PURE__ */ jsx6(Text6, { color: THEME.primary, children: phase })
|
|
12431
12438
|
] }),
|
|
12432
12439
|
/* @__PURE__ */ jsxs5(Text6, { color: THEME.text.muted, children: [
|
|
12433
12440
|
"Targets: ",
|
|
@@ -12485,7 +12492,7 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
12485
12492
|
inputRequestRef.current = inputRequest;
|
|
12486
12493
|
const handleExit = useCallback4(() => {
|
|
12487
12494
|
const ir = inputRequestRef.current;
|
|
12488
|
-
if (ir.
|
|
12495
|
+
if (ir.status === "active") ir.resolve(null);
|
|
12489
12496
|
cleanupAllProcesses().catch(() => {
|
|
12490
12497
|
});
|
|
12491
12498
|
exit();
|
|
@@ -12549,8 +12556,29 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
12549
12556
|
addMessage("system", "No findings.");
|
|
12550
12557
|
break;
|
|
12551
12558
|
}
|
|
12552
|
-
|
|
12553
|
-
findings.forEach((f) =>
|
|
12559
|
+
const findingLines = [`\u2500\u2500\u2500 ${findings.length} Findings \u2500\u2500\u2500`, ""];
|
|
12560
|
+
findings.forEach((f, i) => {
|
|
12561
|
+
const verified = f.isVerified ? `[${ICONS.success}] Verified` : `[${ICONS.warning}] Unverified`;
|
|
12562
|
+
const atk = f.attackPattern ? ` | ATT&CK: ${f.attackPattern}` : "";
|
|
12563
|
+
findingLines.push(`[${i + 1}] [${f.severity.toUpperCase()}] ${f.title}`);
|
|
12564
|
+
findingLines.push(` ${verified}${atk}`);
|
|
12565
|
+
if (f.affected.length > 0) {
|
|
12566
|
+
findingLines.push(` Affected: ${f.affected.join(", ")}`);
|
|
12567
|
+
}
|
|
12568
|
+
if (f.description) {
|
|
12569
|
+
findingLines.push(` ${f.description}`);
|
|
12570
|
+
}
|
|
12571
|
+
if (f.evidence.length > 0) {
|
|
12572
|
+
findingLines.push(` Evidence:`);
|
|
12573
|
+
f.evidence.slice(0, 3).forEach((e) => {
|
|
12574
|
+
const preview = e.length > 120 ? e.slice(0, 120) + "..." : e;
|
|
12575
|
+
findingLines.push(` \u25B8 ${preview}`);
|
|
12576
|
+
});
|
|
12577
|
+
if (f.evidence.length > 3) findingLines.push(` ... +${f.evidence.length - 3} more`);
|
|
12578
|
+
}
|
|
12579
|
+
findingLines.push("");
|
|
12580
|
+
});
|
|
12581
|
+
addMessage("system", findingLines.join("\n"));
|
|
12554
12582
|
break;
|
|
12555
12583
|
case UI_COMMANDS.ASSETS:
|
|
12556
12584
|
case UI_COMMANDS.ASSETS_SHORT:
|
|
@@ -12614,17 +12642,17 @@ ${procData.stdout || "(no output)"}
|
|
|
12614
12642
|
}, [addMessage, executeTask, handleCommand]);
|
|
12615
12643
|
const handleSecretSubmit = useCallback4((value) => {
|
|
12616
12644
|
const ir = inputRequestRef.current;
|
|
12617
|
-
if (
|
|
12645
|
+
if (ir.status !== "active") return;
|
|
12618
12646
|
const displayText = ir.isPassword ? "\u2022".repeat(value.length) : value;
|
|
12619
12647
|
const promptLabel = ir.prompt || "Input";
|
|
12620
12648
|
addMessage("system", `\u21B3 ${promptLabel} ${displayText}`);
|
|
12621
12649
|
ir.resolve(value);
|
|
12622
|
-
setInputRequest({
|
|
12650
|
+
setInputRequest({ status: "inactive" });
|
|
12623
12651
|
setSecretInput("");
|
|
12624
12652
|
}, [addMessage, setInputRequest]);
|
|
12625
12653
|
useInput2(useCallback4((ch, key) => {
|
|
12626
12654
|
if (key.escape) {
|
|
12627
|
-
if (inputRequestRef.current.
|
|
12655
|
+
if (inputRequestRef.current.status === "active") cancelInputRequest();
|
|
12628
12656
|
else if (isProcessingRef.current) abort();
|
|
12629
12657
|
}
|
|
12630
12658
|
if (key.ctrl && ch === "c") handleExit();
|
|
@@ -12711,9 +12739,9 @@ program.command("interactive", { isDefault: true }).alias("i").description("Star
|
|
|
12711
12739
|
const opts = program.opts();
|
|
12712
12740
|
const skipPermissions = opts.dangerouslySkipPermissions || false;
|
|
12713
12741
|
console.clear();
|
|
12714
|
-
console.log(
|
|
12742
|
+
console.log(chalk.hex(THEME.primary)(ASCII_BANNER));
|
|
12715
12743
|
console.log(
|
|
12716
|
-
" " + chalk.hex(THEME.text.secondary)(`v${APP_VERSION}`) + chalk.hex(THEME.text.muted)(" \u2502 ") + chalk.hex(THEME.
|
|
12744
|
+
" " + chalk.hex(THEME.text.secondary)(`v${APP_VERSION}`) + chalk.hex(THEME.text.muted)(" \u2502 ") + chalk.hex(THEME.primary)("Type /help for commands") + "\n"
|
|
12717
12745
|
);
|
|
12718
12746
|
if (skipPermissions) {
|
|
12719
12747
|
console.log(chalk.hex(THEME.status.error)("[!] WARNING: Running with --dangerously-skip-permissions"));
|
|
@@ -12733,11 +12761,11 @@ program.command("interactive", { isDefault: true }).alias("i").description("Star
|
|
|
12733
12761
|
program.command("run <objective>").alias("r").description("Run a single objective and exit").option("-o, --output <file>", "Output file for results").option("--max-steps <n>", "Maximum number of steps", String(CLI_DEFAULT.MAX_STEPS)).action(async (objective, options) => {
|
|
12734
12762
|
const opts = program.opts();
|
|
12735
12763
|
const skipPermissions = opts.dangerouslySkipPermissions || false;
|
|
12736
|
-
console.log(
|
|
12764
|
+
console.log(chalk.hex(THEME.primary)(ASCII_BANNER));
|
|
12737
12765
|
if (skipPermissions) {
|
|
12738
12766
|
console.log(chalk.hex(THEME.status.error)("[!] WARNING: Running with --dangerously-skip-permissions\n"));
|
|
12739
12767
|
}
|
|
12740
|
-
console.log(chalk.hex(THEME.
|
|
12768
|
+
console.log(chalk.hex(THEME.primary)(`[target] Objective: ${objective}
|
|
12741
12769
|
`));
|
|
12742
12770
|
const agent = AgentFactory.createMainAgent(skipPermissions);
|
|
12743
12771
|
if (skipPermissions) {
|
|
@@ -12759,7 +12787,7 @@ program.command("run <objective>").alias("r").description("Run a single objectiv
|
|
|
12759
12787
|
if (options.output) {
|
|
12760
12788
|
const fs = await import("fs/promises");
|
|
12761
12789
|
await fs.writeFile(options.output, JSON.stringify({ result: result2 }, null, 2));
|
|
12762
|
-
console.log(chalk.hex(THEME.
|
|
12790
|
+
console.log(chalk.hex(THEME.primary)(`
|
|
12763
12791
|
[+] Report saved to: ${options.output}`));
|
|
12764
12792
|
}
|
|
12765
12793
|
await shutdown(0);
|
|
@@ -12773,8 +12801,8 @@ program.command("run <objective>").alias("r").description("Run a single objectiv
|
|
|
12773
12801
|
program.command("scan <target>").description("Quick scan a target").option("-s, --scan-type <type>", `Scan type (${CLI_SCAN_TYPES.join("|")})`, CLI_DEFAULT.SCAN_TYPE).option("-p, --ports <ports>", "Specific ports to scan").action(async (target, options) => {
|
|
12774
12802
|
const opts = program.opts();
|
|
12775
12803
|
const skipPermissions = opts.dangerouslySkipPermissions || false;
|
|
12776
|
-
console.log(
|
|
12777
|
-
console.log(chalk.hex(THEME.
|
|
12804
|
+
console.log(chalk.hex(THEME.primary)(ASCII_BANNER));
|
|
12805
|
+
console.log(chalk.hex(THEME.primary)(`
|
|
12778
12806
|
[scan] Target: ${target} (${options.scanType})
|
|
12779
12807
|
`));
|
|
12780
12808
|
const agent = AgentFactory.createMainAgent(skipPermissions);
|
|
@@ -12796,11 +12824,11 @@ program.command("scan <target>").description("Quick scan a target").option("-s,
|
|
|
12796
12824
|
}
|
|
12797
12825
|
});
|
|
12798
12826
|
program.command("help-extended").description("Show extended help with examples").action(() => {
|
|
12799
|
-
console.log(
|
|
12827
|
+
console.log(chalk.hex(THEME.primary)(ASCII_BANNER));
|
|
12800
12828
|
console.log(`
|
|
12801
|
-
${chalk.hex(THEME.
|
|
12829
|
+
${chalk.hex(THEME.primary)(APP_NAME + " - Autonomous Penetration Testing AI")}
|
|
12802
12830
|
|
|
12803
|
-
${chalk.hex(THEME.status.warning)("Usage:")}
|
|
12831
|
+
${chalk.hex(THEME.status.warning)("Usage:")}
|
|
12804
12832
|
|
|
12805
12833
|
${chalk.hex(THEME.status.success)("$ pentesting")} Start interactive mode
|
|
12806
12834
|
${chalk.hex(THEME.status.success)("$ pentesting -t 192.168.1.1")} Start with target
|
|
@@ -12808,24 +12836,24 @@ ${chalk.hex(THEME.status.warning)("Usage:")}
|
|
|
12808
12836
|
|
|
12809
12837
|
${chalk.hex(THEME.status.warning)("Commands:")}
|
|
12810
12838
|
|
|
12811
|
-
${chalk.hex(THEME.
|
|
12812
|
-
${chalk.hex(THEME.
|
|
12813
|
-
${chalk.hex(THEME.
|
|
12839
|
+
${chalk.hex(THEME.primary)("pentesting")} Interactive TUI mode
|
|
12840
|
+
${chalk.hex(THEME.primary)("pentesting run <objective>")} Run single objective
|
|
12841
|
+
${chalk.hex(THEME.primary)("pentesting scan <target>")} Quick scan target
|
|
12814
12842
|
|
|
12815
12843
|
${chalk.hex(THEME.status.warning)("Options:")}
|
|
12816
12844
|
|
|
12817
|
-
${chalk.hex(THEME.
|
|
12818
|
-
${chalk.hex(THEME.
|
|
12819
|
-
${chalk.hex(THEME.
|
|
12845
|
+
${chalk.hex(THEME.primary)("--dangerously-skip-permissions")} Skip all permission prompts
|
|
12846
|
+
${chalk.hex(THEME.primary)("-t, --target <ip>")} Set target
|
|
12847
|
+
${chalk.hex(THEME.primary)("-o, --output <file>")} Save results to file
|
|
12820
12848
|
|
|
12821
12849
|
${chalk.hex(THEME.status.warning)("Interactive Commands:")}
|
|
12822
12850
|
|
|
12823
|
-
${chalk.hex(THEME.
|
|
12824
|
-
${chalk.hex(THEME.
|
|
12825
|
-
${chalk.hex(THEME.
|
|
12826
|
-
${chalk.hex(THEME.
|
|
12827
|
-
${chalk.hex(THEME.
|
|
12828
|
-
${chalk.hex(THEME.
|
|
12851
|
+
${chalk.hex(THEME.primary)("/target <ip>")} Set target
|
|
12852
|
+
${chalk.hex(THEME.primary)("/start")} Start autonomous mode
|
|
12853
|
+
${chalk.hex(THEME.primary)("/config")} Manage configuration
|
|
12854
|
+
${chalk.hex(THEME.primary)("/hint <text>")} Provide hint
|
|
12855
|
+
${chalk.hex(THEME.primary)("/findings")} Show findings
|
|
12856
|
+
${chalk.hex(THEME.primary)("/reset")} Reset session
|
|
12829
12857
|
|
|
12830
12858
|
${chalk.hex(THEME.status.warning)("Examples:")}
|
|
12831
12859
|
|
|
@@ -12840,9 +12868,9 @@ ${chalk.hex(THEME.status.warning)("Examples:")}
|
|
|
12840
12868
|
|
|
12841
12869
|
${chalk.hex(THEME.status.warning)("Environment:")}
|
|
12842
12870
|
|
|
12843
|
-
${chalk.hex(THEME.
|
|
12844
|
-
${chalk.hex(THEME.
|
|
12845
|
-
${chalk.hex(THEME.
|
|
12871
|
+
${chalk.hex(THEME.primary)("PENTEST_API_KEY")} Required - LLM API key
|
|
12872
|
+
${chalk.hex(THEME.primary)("PENTEST_BASE_URL")} Optional - AI API base URL
|
|
12873
|
+
${chalk.hex(THEME.primary)("PENTEST_MODEL")} Optional - Model override
|
|
12846
12874
|
`);
|
|
12847
12875
|
});
|
|
12848
12876
|
program.parse();
|