Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions backend/src/services/ProcessManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ interface PublicProcessInfo {

export class ProcessManager {
private static instance: ProcessManager;
private allowedCommands = new Set(["caldera", "start_maip.sh", "start_maip_iframe.sh", "docker", "python3", "bash", "sh", "./start-client.sh", "cmd"]);
private allowedCommands = new Set(["caldera", "start_maip.sh", "start_maip_iframe.sh", "docker", "python3", "bash", "sh", "./start-client.sh", "cmd", "nmap", "hydra", "dirb"]);
private processes: Map<string, ProcessInfo> = new Map();
private isWindows: boolean;
private terminalManager: TerminalManager;
Expand Down Expand Up @@ -394,8 +394,8 @@ export class ProcessManager {
if (useShell) {
// Pour les commandes shell (comme cd), utiliser les arguments tels quels
allArgs = args;
} else if (program === 'docker') {
// Pour Docker, ne pas ajouter les paramètres automatiquement
} else if (program === 'docker' || ['nmap','hydra','dirb','masscan','netcat','nc','gobuster','sqlmap','nikto'].includes(program)) {
// Docker + network CLI tools: buildAttackCommand already produced the full command; do NOT append params
allArgs = args;
} else if (command.includes('shennina_standalone.py')) {
// Pour Shennina, vérifier si la commande contient déjà tous les paramètres
Expand Down
6 changes: 5 additions & 1 deletion backend/src/services/ScenarioService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -790,8 +790,12 @@ export class ScenarioService {
// Determine final status based on attack results
const hasFailedAttacks = scenario.attacks.some(attack => attack.status === AttackStatus.FAILED);
const hasCompletedAttacks = scenario.attacks.some(attack => attack.status === AttackStatus.COMPLETED);
const allAttacksTerminal = scenario.attacks.every(attack => attack.status === AttackStatus.COMPLETED || attack.status === AttackStatus.FAILED);

if (hasCompletedAttacks && !hasFailedAttacks) {
if (!allAttacksTerminal) {
// Attacks still running asynchronously; keep RUNNING so checkScenarioCompletion finalizes on process exit
scenario.status = AttackStatus.RUNNING;
} else if (hasCompletedAttacks && !hasFailedAttacks) {
scenario.status = AttackStatus.COMPLETED;
} else if (hasCompletedAttacks && hasFailedAttacks) {
scenario.status = AttackStatus.FAILED; // Partial success treated as failed
Expand Down
6 changes: 6 additions & 0 deletions frontend/.env.production
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Production build config (used by `npm run build`; dev uses .env).
# Must point at the hosted origin — Vite loads .env in all modes, so without
# this override the dev localhost:3000 values leak into the production build
# and the browser cannot reach the API/WebSocket.
VITE_API_URL=https://mmt-pentester.montimage.eu
VITE_WS_URL=wss://mmt-pentester.montimage.eu
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const CATEGORIES = [
name: 'All Tools',
description: 'View all available tools',
Icon: WrenchIcon,
count: 6
count: 7
},
{
id: 'FUZZING',
Expand All @@ -29,7 +29,7 @@ const CATEGORIES = [
name: 'Frameworks',
description: 'Complete attack frameworks',
Icon: CommandLineIcon,
count: 2
count: 3
},
{
id: 'Other',
Expand Down
52 changes: 52 additions & 0 deletions frontend/src/constants/ai4cyberTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,58 @@ export const AI4CYBER_TOOLS: AI4CyberTool[] = [
tags: ['fuzzing', 'ai', 'knx', 'iot']
},

// MAG — Montimage Attack Generator
{
id: 'mag',
name: 'mag',
displayName: 'MAG (Montimage Attack Generator)',
description: '26 network, application-layer, credential and amplification attacks via the mmt-attacker CLI (pip install mmt-attacker)',
category: 'framework',
status: 'implemented',
command: (params) => {
const attack = params['attack'] || 'syn-flood';
const targetIp = params['target-ip'] || '192.168.1.1';
const targetPort = params['target-port'] ? ` --target-port ${params['target-port']}` : '';
const extra = params['extra-args'] ? ` ${params['extra-args']}` : '';
return `bash tools/mag/run_mag.sh ${attack} --target-ip ${targetIp}${targetPort}${extra}`;
},
parameters: {
'attack': {
label: 'Attack Type',
type: 'select',
options: [
'syn-flood', 'udp-flood', 'icmp-flood', 'ping-of-death',
'arp-spoof', 'dhcp-starvation',
'http-dos', 'http-flood', 'slowloris',
'ssh-brute-force', 'ftp-brute-force',
'dns-amplification', 'ntp-amplification',
'pcap-replay'
],
default: 'syn-flood',
required: true,
description: 'MAG attack to execute'
},
'target-ip': {
label: 'Target IP',
type: 'target',
required: true,
description: 'Target from scenario targets'
},
'target-port': {
label: 'Target Port',
type: 'number',
description: 'Target port (attack-dependent)'
},
'extra-args': {
label: 'Extra Arguments',
type: 'string',
description: 'Additional CLI flags (e.g. --count 500 --threads 10)'
}
},
estimatedDuration: '1-10 minutes',
tags: ['framework', 'network', 'dos', 'brute-force', 'amplification', 'mitm', 'montimage']
},

// FRAMEWORK
{
id: 'sheninna',
Expand Down
1 change: 1 addition & 0 deletions frontend/src/constants/toolMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export function getAttackDisplayNameFromParams(
// Short display names for known attacks/tools
const shortNames: Record<string, string> = {
shennina: 'Shennina Scan',
mag: 'MAG Attack',
gan_fuzzer: 'GAN Fuzzing',
nmap: 'Nmap Scan',
sqlmap: 'SQL Injection Test',
Expand Down
231 changes: 231 additions & 0 deletions frontend/src/constants/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,237 @@ export const TOOLS: Tool[] = [
]
}
},
{
id: "mag",
name: "MAG (Montimage Attack Generator)",
description: "26 network, application-layer, credential and amplification attacks via the mmt-attacker CLI",
type: "FRAMEWORK",
status: "implemented",
attacks: [
// ── Setup ────────────────────────────────────────────────────────────
{
id: "mag-setup",
name: "Setup / List Attacks",
description: "Install mmt-attacker (if needed) and list all 26 available attack types",
command: (_paramValues: Record<string, string>) =>
"bash tools/mag/setup.sh",
parameters: {}
},
// ── Network Layer ─────────────────────────────────────────────────────
{
id: "mag-syn-flood",
name: "SYN Flood",
description: "TCP SYN flood — exhausts server connection tables to cause denial of service",
command: (paramValues: Record<string, string>) => {
const ip = paramValues["target-ip"] || "192.168.1.1";
const port = paramValues["target-port"] || "80";
const count = paramValues["count"] || "500";
return `bash tools/mag/run_mag.sh syn-flood --target-ip ${ip} --target-port ${port} --count ${count}`;
},
parameters: {
"target-ip": { label: "Target IP", type: "target", default: "192.168.1.1", required: true, description: "IP of the target host" },
"target-port": { label: "Target Port", type: "number", default: "80", required: false, description: "TCP port (default: 80)" },
"count": { label: "Packet Count",type: "number", default: "500", required: false, description: "Number of SYN packets to send" }
}
},
{
id: "mag-udp-flood",
name: "UDP Flood",
description: "High-volume UDP flood targeting a specific port",
command: (paramValues: Record<string, string>) => {
const ip = paramValues["target-ip"] || "192.168.1.1";
const port = paramValues["target-port"] || "53";
const count = paramValues["count"] || "500";
return `bash tools/mag/run_mag.sh udp-flood --target-ip ${ip} --target-port ${port} --count ${count}`;
},
parameters: {
"target-ip": { label: "Target IP", type: "target", default: "192.168.1.1", required: true, description: "IP of the target host" },
"target-port": { label: "Target Port", type: "number", default: "53", required: false, description: "UDP port (default: 53)" },
"count": { label: "Packet Count",type: "number", default: "500", required: false, description: "Number of UDP packets to send" }
}
},
{
id: "mag-icmp-flood",
name: "ICMP Flood",
description: "ICMP echo-request flood (Ping flood) to saturate bandwidth",
command: (paramValues: Record<string, string>) => {
const ip = paramValues["target-ip"] || "192.168.1.1";
const count = paramValues["count"] || "500";
return `bash tools/mag/run_mag.sh icmp-flood --target-ip ${ip} --count ${count}`;
},
parameters: {
"target-ip": { label: "Target IP", type: "target", default: "192.168.1.1", required: true, description: "IP of the target host" },
"count": { label: "Packet Count",type: "number", default: "500", required: false, description: "Number of ICMP packets to send" }
}
},
{
id: "mag-ping-of-death",
name: "Ping of Death",
description: "Oversized ICMP packet attack that can crash or freeze vulnerable hosts",
command: (paramValues: Record<string, string>) => {
const ip = paramValues["target-ip"] || "192.168.1.1";
const count = paramValues["count"] || "10";
return `bash tools/mag/run_mag.sh ping-of-death --target-ip ${ip} --count ${count}`;
},
parameters: {
"target-ip": { label: "Target IP", type: "target", default: "192.168.1.1", required: true, description: "IP of the target host" },
"count": { label: "Packet Count",type: "number", default: "10", required: false, description: "Number of oversized ICMP packets" }
}
},
{
id: "mag-arp-spoof",
name: "ARP Spoofing (MITM)",
description: "Poisons ARP caches to redirect traffic through the attacker (man-in-the-middle)",
command: (paramValues: Record<string, string>) => {
const ip = paramValues["target-ip"] || "192.168.1.100";
const gw = paramValues["gateway-ip"] || "192.168.1.1";
return `bash tools/mag/run_mag.sh arp-spoof --target-ip ${ip} --gateway-ip ${gw}`;
},
parameters: {
"target-ip": { label: "Target IP", type: "target", default: "192.168.1.100", required: true, description: "Victim IP to ARP-poison" },
"gateway-ip": { label: "Gateway IP", type: "string", default: "192.168.1.1", required: true, description: "Default gateway IP" }
}
},
{
id: "mag-dhcp-starvation",
name: "DHCP Starvation",
description: "Exhausts the DHCP pool with forged DISCOVER requests so new clients cannot get an IP",
command: (paramValues: Record<string, string>) => {
const iface = paramValues["interface"] || "eth0";
const count = paramValues["count"] || "200";
return `bash tools/mag/run_mag.sh dhcp-starvation --interface ${iface} --count ${count}`;
},
parameters: {
"interface": { label: "Network Interface", type: "string", default: "eth0", required: true, description: "Network interface to send forged DHCP requests on" },
"count": { label: "Request Count", type: "number", default: "200", required: false, description: "Number of fake DHCP DISCOVER packets" }
}
},
// ── Application Layer ─────────────────────────────────────────────────
{
id: "mag-http-dos",
name: "HTTP DoS",
description: "Multi-threaded HTTP request flood targeting a web endpoint",
command: (paramValues: Record<string, string>) => {
const url = paramValues["target-url"] || "http://192.168.1.1";
const threads = paramValues["threads"] || "10";
return `bash tools/mag/run_mag.sh http-dos --target-url ${url} --threads ${threads}`;
},
parameters: {
"target-url": { label: "Target URL", type: "string", default: "http://192.168.1.1", required: true, description: "Full URL of the target endpoint" },
"threads": { label: "Threads", type: "number", default: "10", required: false, description: "Number of concurrent threads" }
}
},
{
id: "mag-http-flood",
name: "HTTP Flood",
description: "Layer-7 HTTP flood sending a large number of GET/POST requests",
command: (paramValues: Record<string, string>) => {
const url = paramValues["target-url"] || "http://192.168.1.1";
const threads = paramValues["threads"] || "10";
const count = paramValues["count"] || "1000";
return `bash tools/mag/run_mag.sh http-flood --target-url ${url} --threads ${threads} --count ${count}`;
},
parameters: {
"target-url": { label: "Target URL", type: "string", default: "http://192.168.1.1", required: true, description: "Full URL of the target endpoint" },
"threads": { label: "Threads", type: "number", default: "10", required: false, description: "Number of concurrent threads" },
"count": { label: "Request Count",type: "number", default: "1000", required: false, description: "Total number of HTTP requests" }
}
},
{
id: "mag-slowloris",
name: "Slowloris",
description: "Keeps many HTTP connections open using partial requests, exhausting the web server's thread pool",
command: (paramValues: Record<string, string>) => {
const ip = paramValues["target-ip"] || "192.168.1.1";
const port = paramValues["target-port"] || "80";
return `bash tools/mag/run_mag.sh slowloris --target-ip ${ip} --target-port ${port}`;
},
parameters: {
"target-ip": { label: "Target IP", type: "target", default: "192.168.1.1", required: true, description: "IP of the web server" },
"target-port": { label: "Target Port", type: "number", default: "80", required: false, description: "HTTP port (80 or 443)" }
}
},
// ── Credential Attacks ────────────────────────────────────────────────
{
id: "mag-ssh-brute-force",
name: "SSH Brute Force",
description: "Dictionary-based brute-force against an SSH service",
command: (paramValues: Record<string, string>) => {
const ip = paramValues["target-ip"] || "192.168.1.1";
const port = paramValues["target-port"] || "22";
const username = paramValues["username"] || "root";
return `bash tools/mag/run_mag.sh ssh-brute-force --target-ip ${ip} --target-port ${port} --username ${username}`;
},
parameters: {
"target-ip": { label: "Target IP", type: "target", default: "192.168.1.1", required: true, description: "IP of the SSH server" },
"target-port": { label: "SSH Port", type: "number", default: "22", required: false, description: "SSH port (default: 22)" },
"username": { label: "Username", type: "string", default: "root", required: false, description: "Username to brute-force" }
}
},
{
id: "mag-ftp-brute-force",
name: "FTP Brute Force",
description: "Dictionary-based brute-force against an FTP service",
command: (paramValues: Record<string, string>) => {
const ip = paramValues["target-ip"] || "192.168.1.1";
const port = paramValues["target-port"] || "21";
const username = paramValues["username"] || "anonymous";
return `bash tools/mag/run_mag.sh ftp-brute-force --target-ip ${ip} --target-port ${port} --username ${username}`;
},
parameters: {
"target-ip": { label: "Target IP", type: "target", default: "192.168.1.1", required: true, description: "IP of the FTP server" },
"target-port": { label: "FTP Port", type: "number", default: "21", required: false, description: "FTP port (default: 21)" },
"username": { label: "Username", type: "string", default: "anonymous", required: false, description: "Username to brute-force" }
}
},
// ── Amplification Attacks ─────────────────────────────────────────────
{
id: "mag-dns-amplification",
name: "DNS Amplification",
description: "Exploits open DNS resolvers to amplify traffic 50-100× toward the target",
command: (paramValues: Record<string, string>) => {
const ip = paramValues["target-ip"] || "192.168.1.1";
return `bash tools/mag/run_mag.sh dns-amplification --target-ip ${ip}`;
},
parameters: {
"target-ip": { label: "Target IP", type: "target", default: "192.168.1.1", required: true, description: "Spoofed victim IP — amplified responses will be sent here" }
}
},
{
id: "mag-ntp-amplification",
name: "NTP Amplification",
description: "Exploits NTP monlist to amplify traffic up to 500× toward the target",
command: (paramValues: Record<string, string>) => {
const ip = paramValues["target-ip"] || "192.168.1.1";
return `bash tools/mag/run_mag.sh ntp-amplification --target-ip ${ip}`;
},
parameters: {
"target-ip": { label: "Target IP", type: "target", default: "192.168.1.1", required: true, description: "Spoofed victim IP — amplified NTP responses will be sent here" }
}
},
// ── Protocol / Replay ─────────────────────────────────────────────────
{
id: "mag-pcap-replay",
name: "PCAP Replay",
description: "Reproduce previously captured network traffic at configurable speed",
command: (paramValues: Record<string, string>) => {
const file = paramValues["pcap-file"] || "capture.pcap";
const iface = paramValues["interface"] || "eth0";
const speed = paramValues["speed"] || "1.0";
return `bash tools/mag/run_mag.sh pcap-replay --pcap-file ${file} --interface ${iface} --speed ${speed}`;
},
parameters: {
"pcap-file": { label: "PCAP File", type: "string", default: "capture.pcap", required: true, description: "Path to the .pcap file to replay" },
"interface": { label: "Interface", type: "string", default: "eth0", required: true, description: "Network interface to replay on" },
"speed": { label: "Playback Speed", type: "string", default: "1.0", required: false, description: "Speed multiplier (e.g. 2.0 = twice original speed)" }
}
}
],
command: function(paramValues: Record<string, string>) {
return this.attacks[0].command(paramValues);
},
parameters: {}
},
{
id: "caldera",
name: "Caldera",
Expand Down
Loading
Loading