pentesting 0.56.2 → 0.56.4
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 +131 -26
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -711,7 +711,7 @@ var INPUT_PROMPT_PATTERNS = [
|
|
|
711
711
|
|
|
712
712
|
// src/shared/constants/agent.ts
|
|
713
713
|
var APP_NAME = "Pentest AI";
|
|
714
|
-
var APP_VERSION = "0.56.
|
|
714
|
+
var APP_VERSION = "0.56.4";
|
|
715
715
|
var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
|
|
716
716
|
var LLM_ROLES = {
|
|
717
717
|
SYSTEM: "system",
|
|
@@ -14803,20 +14803,28 @@ var createSessionCommands = (ctx) => ({
|
|
|
14803
14803
|
|
|
14804
14804
|
// src/platform/tui/hooks/commands/target-commands.ts
|
|
14805
14805
|
var createTargetCommands = (ctx) => ({
|
|
14806
|
-
[UI_COMMANDS.TARGET]: (args) => {
|
|
14806
|
+
[UI_COMMANDS.TARGET]: async (args) => {
|
|
14807
14807
|
if (!args[0]) {
|
|
14808
14808
|
ctx.addMessage("error", "Usage: /target <ip>");
|
|
14809
14809
|
return;
|
|
14810
14810
|
}
|
|
14811
|
+
if (ctx.agent.getState().getTargets().size > 0) {
|
|
14812
|
+
await ctx.agent.resetSession();
|
|
14813
|
+
ctx.addMessage("system", "Previous target data cleared. Starting fresh session for the new target.");
|
|
14814
|
+
}
|
|
14811
14815
|
ctx.agent.addTarget(args[0]);
|
|
14812
14816
|
ctx.agent.setScope([args[0]]);
|
|
14813
14817
|
ctx.addMessage("system", `Target \u2192 ${args[0]}`);
|
|
14814
14818
|
},
|
|
14815
|
-
[UI_COMMANDS.TARGET_SHORT]: (args) => {
|
|
14819
|
+
[UI_COMMANDS.TARGET_SHORT]: async (args) => {
|
|
14816
14820
|
if (!args[0]) {
|
|
14817
14821
|
ctx.addMessage("error", "Usage: /target <ip>");
|
|
14818
14822
|
return;
|
|
14819
14823
|
}
|
|
14824
|
+
if (ctx.agent.getState().getTargets().size > 0) {
|
|
14825
|
+
await ctx.agent.resetSession();
|
|
14826
|
+
ctx.addMessage("system", "Previous target data cleared. Starting fresh session for the new target.");
|
|
14827
|
+
}
|
|
14820
14828
|
ctx.agent.addTarget(args[0]);
|
|
14821
14829
|
ctx.agent.setScope([args[0]]);
|
|
14822
14830
|
ctx.addMessage("system", `Target \u2192 ${args[0]}`);
|
|
@@ -14929,6 +14937,15 @@ var boxLine = (content, width) => {
|
|
|
14929
14937
|
const truncated = content.length > inner ? content.slice(0, inner - 1) + "\u2026" : content;
|
|
14930
14938
|
return `\u2502 ${truncated.padEnd(inner - 1)}`;
|
|
14931
14939
|
};
|
|
14940
|
+
var formatTargetLine = (target) => {
|
|
14941
|
+
if (target.ports.length === 0) return target.ip;
|
|
14942
|
+
const portList = target.ports.map((p) => `${p.port}`).join(", ");
|
|
14943
|
+
return `${target.ip} \u2192 ${target.ip}:${portList}`;
|
|
14944
|
+
};
|
|
14945
|
+
var formatServiceLabel = (target, port) => {
|
|
14946
|
+
const svc = port.version ? `${port.service}/${port.version}` : port.service;
|
|
14947
|
+
return `${target.ip}:${port.port} (${svc})`;
|
|
14948
|
+
};
|
|
14932
14949
|
var formatFindingsWithFlags = (findings, flags) => {
|
|
14933
14950
|
const findingsOutput = formatFindings(findings);
|
|
14934
14951
|
const flagsOutput = formatFlags(flags);
|
|
@@ -14938,41 +14955,108 @@ ${flagsOutput}`;
|
|
|
14938
14955
|
}
|
|
14939
14956
|
return findingsOutput;
|
|
14940
14957
|
};
|
|
14941
|
-
var formatGraphWithSummary = (
|
|
14958
|
+
var formatGraphWithSummary = (state, findings, flags) => {
|
|
14942
14959
|
const lines = [];
|
|
14943
14960
|
const w = getBoxWidth();
|
|
14944
14961
|
const innerDash = w - 2;
|
|
14945
|
-
|
|
14946
|
-
|
|
14947
|
-
|
|
14948
|
-
|
|
14949
|
-
|
|
14962
|
+
const targets = state.getAllTargets();
|
|
14963
|
+
const graphStats = state.attackGraph.getStats();
|
|
14964
|
+
const allNodes = state.attackGraph.getAllNodes();
|
|
14965
|
+
const hostNodes = allNodes.filter((n) => n.type === NODE_TYPE.HOST);
|
|
14966
|
+
const serviceNodes = allNodes.filter((n) => n.type === NODE_TYPE.SERVICE);
|
|
14967
|
+
const vulnNodes = allNodes.filter((n) => n.type === NODE_TYPE.VULNERABILITY);
|
|
14968
|
+
const hostCount = hostNodes.length || targets.length;
|
|
14969
|
+
const serviceCount = serviceNodes.length || targets.reduce((sum, t) => sum + t.ports.length, 0);
|
|
14970
|
+
const vulnCount = findings.length;
|
|
14971
|
+
const topTitle = "\u2500\u2500\u2500 Attack Graph ";
|
|
14972
|
+
lines.push(`\u250C${topTitle}${"\u2500".repeat(Math.max(0, innerDash - topTitle.length))}\u2510`);
|
|
14973
|
+
lines.push(boxLine(`\u{1F5A5} ${hostCount} \u26A0 ${vulnCount} \u2699 ${serviceCount}`, w));
|
|
14950
14974
|
lines.push(boxLine("", w));
|
|
14951
|
-
lines.push(boxLine(`\
|
|
14952
|
-
|
|
14953
|
-
|
|
14954
|
-
|
|
14955
|
-
|
|
14956
|
-
|
|
14957
|
-
|
|
14975
|
+
lines.push(boxLine(`\u{1F5A5} HOST (${hostCount})`, w));
|
|
14976
|
+
if (targets.length > 0) {
|
|
14977
|
+
for (const t of targets.slice(0, 5)) {
|
|
14978
|
+
lines.push(boxLine(` \u25CB ${formatTargetLine(t)}`, w));
|
|
14979
|
+
}
|
|
14980
|
+
if (targets.length > 5) {
|
|
14981
|
+
lines.push(boxLine(` ... and ${targets.length - 5} more hosts`, w));
|
|
14982
|
+
}
|
|
14983
|
+
} else if (hostNodes.length > 0) {
|
|
14984
|
+
for (const node of hostNodes.slice(0, 5)) {
|
|
14985
|
+
lines.push(boxLine(` \u25CB ${node.label}`, w));
|
|
14986
|
+
}
|
|
14987
|
+
if (hostNodes.length > 5) {
|
|
14988
|
+
lines.push(boxLine(` ... and ${hostNodes.length - 5} more hosts`, w));
|
|
14989
|
+
}
|
|
14990
|
+
} else {
|
|
14991
|
+
lines.push(boxLine(" (no hosts discovered)", w));
|
|
14958
14992
|
}
|
|
14959
|
-
|
|
14960
|
-
|
|
14993
|
+
lines.push(boxLine("", w));
|
|
14994
|
+
lines.push(boxLine(`\u26A0 VULNERABILITY (${vulnCount})`, w));
|
|
14995
|
+
if (findings.length > 0) {
|
|
14996
|
+
const sortedFindings = [...findings].sort((a, b) => b.confidence - a.confidence).slice(0, 5);
|
|
14997
|
+
for (const f of sortedFindings) {
|
|
14998
|
+
const icon = confIcon(f.confidence);
|
|
14999
|
+
const cat = f.category ? ` \u2502 ${f.category}` : "";
|
|
15000
|
+
lines.push(boxLine(` \u25CB ${icon} ${f.title.slice(0, 60)}${f.title.length > 60 ? "..." : ""}`, w));
|
|
15001
|
+
lines.push(boxLine(` ${confLabel(f.confidence).toUpperCase()} \u2502 ${f.severity.toUpperCase()}${cat}`, w));
|
|
15002
|
+
}
|
|
15003
|
+
if (findings.length > 5) {
|
|
15004
|
+
lines.push(boxLine(` ... and ${findings.length - 5} more findings`, w));
|
|
15005
|
+
}
|
|
15006
|
+
} else if (vulnNodes.length > 0) {
|
|
15007
|
+
for (const node of vulnNodes.slice(0, 5)) {
|
|
15008
|
+
lines.push(boxLine(` \u25CB ${node.label}`, w));
|
|
15009
|
+
}
|
|
15010
|
+
if (vulnNodes.length > 5) {
|
|
15011
|
+
lines.push(boxLine(` ... and ${vulnNodes.length - 5} more`, w));
|
|
15012
|
+
}
|
|
15013
|
+
} else {
|
|
15014
|
+
lines.push(boxLine(" (no vulnerabilities found)", w));
|
|
14961
15015
|
}
|
|
14962
15016
|
const cveFindings = findings.filter((f) => f.title.includes("CVE"));
|
|
14963
15017
|
if (cveFindings.length > 0) {
|
|
14964
|
-
|
|
15018
|
+
const cveList = cveFindings.slice(0, 3).map((f) => f.title.match(/CVE-\d{4}-\d+/)?.[0] ?? f.title).join(", ");
|
|
15019
|
+
const suffix = cveFindings.length > 3 ? ` (+${cveFindings.length - 3} more)` : "";
|
|
15020
|
+
lines.push(boxLine(` \u25CB CVE found: ${cveList}${suffix}`, w));
|
|
14965
15021
|
}
|
|
14966
15022
|
lines.push(boxLine("", w));
|
|
14967
|
-
lines.push(boxLine(
|
|
14968
|
-
|
|
15023
|
+
lines.push(boxLine(`\u2699 SERVICE (${serviceCount})`, w));
|
|
15024
|
+
if (targets.length > 0) {
|
|
15025
|
+
let shownServices = 0;
|
|
15026
|
+
const maxShow = 5;
|
|
15027
|
+
for (const t of targets) {
|
|
15028
|
+
for (const p of t.ports) {
|
|
15029
|
+
if (shownServices >= maxShow) break;
|
|
15030
|
+
lines.push(boxLine(` \u25CB ${formatServiceLabel(t, p)}`, w));
|
|
15031
|
+
shownServices++;
|
|
15032
|
+
}
|
|
15033
|
+
if (shownServices >= maxShow) break;
|
|
15034
|
+
}
|
|
15035
|
+
const totalServices = targets.reduce((sum, t) => sum + t.ports.length, 0);
|
|
15036
|
+
if (totalServices > maxShow) {
|
|
15037
|
+
lines.push(boxLine(` ... and ${totalServices - maxShow} more services`, w));
|
|
15038
|
+
}
|
|
15039
|
+
} else if (serviceNodes.length > 0) {
|
|
15040
|
+
for (const node of serviceNodes.slice(0, 5)) {
|
|
15041
|
+
lines.push(boxLine(` \u25CB ${node.label}`, w));
|
|
15042
|
+
}
|
|
15043
|
+
if (serviceNodes.length > 5) {
|
|
15044
|
+
lines.push(boxLine(` ... and ${serviceNodes.length - 5} more`, w));
|
|
15045
|
+
}
|
|
15046
|
+
} else {
|
|
15047
|
+
lines.push(boxLine(" (no services discovered)", w));
|
|
15048
|
+
}
|
|
14969
15049
|
if (flags.length > 0) {
|
|
14970
15050
|
lines.push(boxLine("", w));
|
|
14971
15051
|
lines.push(boxLine(`\u{1F3F4} Captured: ${flags.length}`, w));
|
|
14972
15052
|
}
|
|
14973
15053
|
lines.push(boxLine("", w));
|
|
14974
|
-
|
|
14975
|
-
lines.push(
|
|
15054
|
+
const midTitle = "\u2500\u2500\u2500 Summary ";
|
|
15055
|
+
lines.push(`\u251C${midTitle}${"\u2500".repeat(Math.max(0, innerDash - midTitle.length))}\u2524`);
|
|
15056
|
+
lines.push(boxLine(
|
|
15057
|
+
`Nodes: ${graphStats.nodes} | Edges: ${graphStats.edges} | Succeeded: ${graphStats.succeeded} | Failed: ${graphStats.failed} | Chains: ${graphStats.chains}`,
|
|
15058
|
+
w
|
|
15059
|
+
));
|
|
14976
15060
|
lines.push(`\u2514${"\u2500".repeat(innerDash)}\u2518`);
|
|
14977
15061
|
return lines.join("\n");
|
|
14978
15062
|
};
|
|
@@ -15031,7 +15115,7 @@ ${procData.stdout || "(no output)"}
|
|
|
15031
15115
|
const flags = state.getFlags();
|
|
15032
15116
|
const graphASCII = state.attackGraph.toASCII();
|
|
15033
15117
|
if (state.attackGraph.isEmpty() && (findings.length > 0 || flags.length > 0)) {
|
|
15034
|
-
ctx.showModal("graph", formatGraphWithSummary(
|
|
15118
|
+
ctx.showModal("graph", formatGraphWithSummary(state, findings, flags));
|
|
15035
15119
|
} else {
|
|
15036
15120
|
let output = graphASCII;
|
|
15037
15121
|
if (flags.length > 0) {
|
|
@@ -15046,7 +15130,7 @@ ${procData.stdout || "(no output)"}
|
|
|
15046
15130
|
const flags = state.getFlags();
|
|
15047
15131
|
const graphASCII = state.attackGraph.toASCII();
|
|
15048
15132
|
if (state.attackGraph.isEmpty() && (findings.length > 0 || flags.length > 0)) {
|
|
15049
|
-
ctx.showModal("graph", formatGraphWithSummary(
|
|
15133
|
+
ctx.showModal("graph", formatGraphWithSummary(state, findings, flags));
|
|
15050
15134
|
} else {
|
|
15051
15135
|
let output = graphASCII;
|
|
15052
15136
|
if (flags.length > 0) {
|
|
@@ -16306,6 +16390,27 @@ var ChatInput = memo10(({
|
|
|
16306
16390
|
setSelectedIdx(0);
|
|
16307
16391
|
setInputKey((k) => k + 1);
|
|
16308
16392
|
}, []);
|
|
16393
|
+
const onSubmitRef = useRef8(onSubmit);
|
|
16394
|
+
onSubmitRef.current = onSubmit;
|
|
16395
|
+
const wrappedOnSubmit = useCallback9((val) => {
|
|
16396
|
+
if (showPreviewRef.current) {
|
|
16397
|
+
const sug = suggestionsRef.current;
|
|
16398
|
+
if (!sug.length) {
|
|
16399
|
+
onSubmitRef.current(val);
|
|
16400
|
+
return;
|
|
16401
|
+
}
|
|
16402
|
+
const best = sug[Math.min(selectedIdxRef.current, sug.length - 1)];
|
|
16403
|
+
if (best.args) {
|
|
16404
|
+
completeCommand(selectedIdxRef.current);
|
|
16405
|
+
} else {
|
|
16406
|
+
const completed = `/${best.name}`;
|
|
16407
|
+
onChangeRef.current(completed);
|
|
16408
|
+
onSubmitRef.current(completed);
|
|
16409
|
+
}
|
|
16410
|
+
return;
|
|
16411
|
+
}
|
|
16412
|
+
onSubmitRef.current(val);
|
|
16413
|
+
}, [completeCommand]);
|
|
16309
16414
|
useInput3(useCallback9((_input, key) => {
|
|
16310
16415
|
if (inputRequestRef.current.status === "active") return;
|
|
16311
16416
|
const sug = suggestionsRef.current;
|
|
@@ -16349,7 +16454,7 @@ var ChatInput = memo10(({
|
|
|
16349
16454
|
inputKey,
|
|
16350
16455
|
value,
|
|
16351
16456
|
onChange,
|
|
16352
|
-
onSubmit,
|
|
16457
|
+
onSubmit: wrappedOnSubmit,
|
|
16353
16458
|
placeholder
|
|
16354
16459
|
}
|
|
16355
16460
|
)
|