From b3efd646f6043be0e46bfea251c52930d6d9651e Mon Sep 17 00:00:00 2001 From: anti Date: Wed, 15 Apr 2026 16:37:54 -0400 Subject: [PATCH] feat: replace tool attribution stat with dedicated DETECTED TOOLS block --- decnet_web/src/components/AttackerDetail.tsx | 77 +++++++++++++------- 1 file changed, 49 insertions(+), 28 deletions(-) diff --git a/decnet_web/src/components/AttackerDetail.tsx b/decnet_web/src/components/AttackerDetail.tsx index 3c7d5e7..3c8eda6 100644 --- a/decnet_web/src/components/AttackerDetail.tsx +++ b/decnet_web/src/components/AttackerDetail.tsx @@ -435,27 +435,8 @@ const KeyValueRow: React.FC<{ label: string; value: React.ReactNode }> = ({ labe ); -const ToolBadges: React.FC<{ tools: string[] }> = ({ tools }) => ( -
- {tools.map(t => ( - - {TOOL_LABELS[t] || t.toUpperCase()} - - ))} -
-); +// Tools detected via beacon timing (C2 frameworks). +const _C2_TOOLS = new Set(['cobalt_strike', 'sliver', 'havoc', 'mythic']); const BehaviorHeadline: React.FC<{ b: AttackerBehavior }> = ({ b }) => { const osLabel = b.os_guess ? (OS_LABELS[b.os_guess] || b.os_guess.toUpperCase()) : '—'; @@ -463,17 +444,56 @@ const BehaviorHeadline: React.FC<{ b: AttackerBehavior }> = ({ b }) => { ? (BEHAVIOR_LABELS[b.behavior_class] || b.behavior_class.toUpperCase()) : 'UNKNOWN'; const behaviorColor = b.behavior_class ? BEHAVIOR_COLORS[b.behavior_class] : undefined; - const tools = b.tool_guesses && b.tool_guesses.length > 0 ? b.tool_guesses : null; return ( -
+
- : '—'} - color={tools ? '#ff6b6b' : undefined} - /> +
+ ); +}; + +const DetectedToolsBlock: React.FC<{ b: AttackerBehavior }> = ({ b }) => { + const tools = b.tool_guesses && b.tool_guesses.length > 0 ? b.tool_guesses : null; + if (!tools) return null; + return ( +
+
+ + + DETECTED TOOLS + +
+
+ {tools.map(t => ( +
+ + {TOOL_LABELS[t] || t.toUpperCase()} + + + {_C2_TOOLS.has(t) ? 'BEACON TIMING' : 'HTTP HEADER'} + +
+ ))} +
); }; @@ -885,6 +905,7 @@ const AttackerDetail: React.FC = () => {
+