1407  Attack Visualization Suite: Core Interactive Tool

Interactive Step-by-Step IoT Attack Animations with Playback Controls

1407.1 Learning Objectives

After using this visualization tool, you will be able to:

  1. Identify six common IoT attack types and their characteristics
  2. Explain the step-by-step progression of each attack
  3. Control attack animations using playback features
  4. Toggle protection modes to compare attack success vs. mitigation
WarningEducational Purpose Only

These visualizations are for educational purposes only to help security professionals and developers understand attack vectors and implement proper defenses. Never use this knowledge for malicious purposes.

Security attacks are ways that bad actors try to break into systems, steal data, or cause problems. Think of it like understanding how a burglar might break into a house - by knowing their methods, you can install better locks and alarms. In IoT, devices like smart thermostats, cameras, and sensors can be targets, so we need to understand the threats to protect them.


TipHow to Use This Tool
  1. Select Attack Type: Click any of the six attack cards (MITM, Replay, DoS, Side-Channel, Firmware, Downgrade) to load that visualization
  2. Control Playback: Use Play/Pause to auto-advance through attack phases, or Step Forward/Back to examine each phase in detail
  3. Toggle Protection: Enable “Protection ON” to see how security controls mitigate each attack
  4. Adjust Speed: Use the speed slider (0.5x to 3x) to control animation pace
  5. Track Progress: Click the progress bar segments to jump to any attack phase

Tips: - Watch the “Attacker Gains” panel to understand what information is compromised at each step - Check “Detection Indicators” for signs that security teams can monitor

1407.2 Attack Visualization Suite

1407.2.1 Attack Animation Visualization

```{ojs}
//| echo: false
//| label: attack-animation-canvas
//| fig-alt: "Animated visualization showing the step-by-step progression of the selected security attack with attacker, victim, and server components"

// Main attack visualization canvas
attackVisualization = {
  const width = 900;
  const height = 500;
  const attack = selectedAttack;
  const step = currentStep;
  const protected = showProtection;

  const svg = d3.create("svg")
    .attr("viewBox", `0 0 ${width} ${height}`)
    .attr("width", "100%")
    .attr("height", height)
    .style("background", "linear-gradient(180deg, #1a1a2e 0%, #16213e 100%)")
    .style("border-radius", "12px")
    .style("box-shadow", "0 4px 20px rgba(0,0,0,0.3)");

  // Add grid pattern for tech feel
  const defs = svg.append("defs");

  const gridPattern = defs.append("pattern")
    .attr("id", "grid")
    .attr("width", 40)
    .attr("height", 40)
    .attr("patternUnits", "userSpaceOnUse");

  gridPattern.append("path")
    .attr("d", "M 40 0 L 0 0 0 40")
    .attr("fill", "none")
    .attr("stroke", "rgba(255,255,255,0.03)")
    .attr("stroke-width", 1);

  svg.append("rect")
    .attr("width", width)
    .attr("height", height)
    .attr("fill", "url(#grid)");

  // Glow filter for active elements
  const glowFilter = defs.append("filter")
    .attr("id", "glow")
    .attr("x", "-50%")
    .attr("y", "-50%")
    .attr("width", "200%")
    .attr("height", "200%");

  glowFilter.append("feGaussianBlur")
    .attr("stdDeviation", "3")
    .attr("result", "coloredBlur");

  const glowMerge = glowFilter.append("feMerge");
  glowMerge.append("feMergeNode").attr("in", "coloredBlur");
  glowMerge.append("feMergeNode").attr("in", "SourceGraphic");

  // Attack-specific entity positions
  const entities = getEntityPositions(attack.id, width, height);

  // Draw entities
  entities.forEach((entity, i) => {
    const group = svg.append("g")
      .attr("transform", `translate(${entity.x}, ${entity.y})`);

    // Entity shadow
    group.append("ellipse")
      .attr("cx", 0)
      .attr("cy", 50)
      .attr("rx", 40)
      .attr("ry", 10)
      .attr("fill", "rgba(0,0,0,0.3)");

    // Entity body based on type
    if (entity.type === "device") {
      // IoT Device
      group.append("rect")
        .attr("x", -30)
        .attr("y", -35)
        .attr("width", 60)
        .attr("height", 70)
        .attr("rx", 8)
        .attr("fill", entity.active && step >= entity.activeStep ? ieeeColors.orange : ieeeColors.teal)
        .attr("stroke", ieeeColors.white)
        .attr("stroke-width", 2)
        .attr("filter", entity.active && step >= entity.activeStep ? "url(#glow)" : "none");

      // Antenna
      group.append("line")
        .attr("x1", 0)
        .attr("y1", -35)
        .attr("x2", 0)
        .attr("y2", -55)
        .attr("stroke", ieeeColors.white)
        .attr("stroke-width", 2);

      group.append("circle")
        .attr("cx", 0)
        .attr("cy", -58)
        .attr("r", 4)
        .attr("fill", ieeeColors.green);

      // Screen
      group.append("rect")
        .attr("x", -20)
        .attr("y", -25)
        .attr("width", 40)
        .attr("height", 25)
        .attr("rx", 3)
        .attr("fill", "#0f1923");

    } else if (entity.type === "attacker") {
      // Attacker (hooded figure)
      group.append("circle")
        .attr("cx", 0)
        .attr("cy", -20)
        .attr("r", 25)
        .attr("fill", ieeeColors.red)
        .attr("filter", step >= entity.activeStep ? "url(#glow)" : "none");

      // Hood
      group.append("path")
        .attr("d", "M -25 -10 Q -30 -45 0 -50 Q 30 -45 25 -10")
        .attr("fill", ieeeColors.red)
        .attr("stroke", "#a93226")
        .attr("stroke-width", 2);

      // Mask eyes
      group.append("rect")
        .attr("x", -15)
        .attr("y", -25)
        .attr("width", 30)
        .attr("height", 8)
        .attr("rx", 4)
        .attr("fill", "#0f1923");

      group.append("circle").attr("cx", -8).attr("cy", -21).attr("r", 2).attr("fill", ieeeColors.orange);
      group.append("circle").attr("cx", 8).attr("cy", -21).attr("r", 2).attr("fill", ieeeColors.orange);

      // Body
      group.append("path")
        .attr("d", "M -20 5 L -30 45 L 30 45 L 20 5 Z")
        .attr("fill", ieeeColors.red)
        .attr("stroke", "#a93226")
        .attr("stroke-width", 2);

    } else if (entity.type === "server") {
      // Server
      group.append("rect")
        .attr("x", -35)
        .attr("y", -45)
        .attr("width", 70)
        .attr("height", 90)
        .attr("rx", 5)
        .attr("fill", entity.active && step >= entity.activeStep ? ieeeColors.orange : ieeeColors.navy)
        .attr("stroke", ieeeColors.white)
        .attr("stroke-width", 2)
        .attr("filter", entity.active && step >= entity.activeStep ? "url(#glow)" : "none");

      // Server slots
      for (let j = 0; j < 4; j++) {
        group.append("rect")
          .attr("x", -28)
          .attr("y", -38 + j * 20)
          .attr("width", 56)
          .attr("height", 14)
          .attr("rx", 2)
          .attr("fill", "#0f1923");

        // Blinking lights
        for (let k = 0; k < 3; k++) {
          group.append("circle")
            .attr("cx", -22 + k * 8)
            .attr("cy", -31 + j * 20)
            .attr("r", 2)
            .attr("fill", j === step % 4 ? ieeeColors.green : ieeeColors.gray);
        }
      }
    } else if (entity.type === "shield") {
      // Protection shield (only shown in protected mode)
      if (protected) {
        group.append("path")
          .attr("d", "M 0 -50 L 35 -35 L 35 15 Q 35 45 0 55 Q -35 45 -35 15 L -35 -35 Z")
          .attr("fill", `${ieeeColors.green}40`)
          .attr("stroke", ieeeColors.green)
          .attr("stroke-width", 3)
          .attr("filter", "url(#glow)");

        group.append("text")
          .attr("x", 0)
          .attr("y", 5)
          .attr("text-anchor", "middle")
          .attr("fill", ieeeColors.green)
          .attr("font-size", "24px")
          .text("🛡️");
      }
    }

    // Entity label
    group.append("text")
      .attr("x", 0)
      .attr("y", 70)
      .attr("text-anchor", "middle")
      .attr("fill", ieeeColors.white)
      .attr("font-size", "14px")
      .attr("font-weight", "600")
      .text(entity.label);
  });

  // Draw attack flow arrows based on current step
  const flows = getAttackFlows(attack.id, step, protected, entities, width, height);

  flows.forEach((flow, i) => {
    if (flow.visible) {
      const path = svg.append("path")
        .attr("d", flow.path)
        .attr("fill", "none")
        .attr("stroke", flow.blocked ? ieeeColors.red : flow.malicious ? ieeeColors.orange : ieeeColors.teal)
        .attr("stroke-width", flow.blocked ? 4 : 3)
        .attr("stroke-dasharray", flow.malicious ? "10,5" : flow.blocked ? "5,5" : "none")
        .attr("marker-end", flow.blocked ? "none" : `url(#arrow-${flow.malicious ? 'orange' : 'teal'})`);

      // Animate packets along path
      if (flow.animated && !flow.blocked) {
        const pathLength = path.node().getTotalLength();

        for (let p = 0; p < 3; p++) {
          const packet = svg.append("circle")
            .attr("r", 6)
            .attr("fill", flow.malicious ? ieeeColors.orange : ieeeColors.teal)
            .attr("filter", "url(#glow)");

          function animatePacket() {
            packet
              .attr("transform", `translate(${path.node().getPointAtLength(0).x}, ${path.node().getPointAtLength(0).y})`)
              .transition()
              .duration(2000 / animationSpeed)
              .delay(p * 600)
              .ease(d3.easeLinear)
              .attrTween("transform", function() {
                return function(t) {
                  const point = path.node().getPointAtLength(t * pathLength);
                  return `translate(${point.x}, ${point.y})`;
                };
              })
              .on("end", animatePacket);
          }

          animatePacket();
        }
      }

      // Flow label
      if (flow.label) {
        const midPoint = path.node().getPointAtLength(path.node().getTotalLength() / 2);
        svg.append("text")
          .attr("x", midPoint.x)
          .attr("y", midPoint.y - 15)
          .attr("text-anchor", "middle")
          .attr("fill", flow.malicious ? ieeeColors.orange : ieeeColors.lightGray)
          .attr("font-size", "11px")
          .attr("font-weight", "500")
          .text(flow.label);
      }

      // Blocked X mark
      if (flow.blocked) {
        const midPoint = path.node().getPointAtLength(path.node().getTotalLength() / 2);
        svg.append("text")
          .attr("x", midPoint.x)
          .attr("y", midPoint.y + 5)
          .attr("text-anchor", "middle")
          .attr("fill", ieeeColors.red)
          .attr("font-size", "30px")
          .attr("font-weight", "bold")
          .text("✕");
      }
    }
  });

  // Arrow markers
  const arrowColors = [
    { id: "teal", color: ieeeColors.teal },
    { id: "orange", color: ieeeColors.orange }
  ];

  arrowColors.forEach(ac => {
    defs.append("marker")
      .attr("id", `arrow-${ac.id}`)
      .attr("viewBox", "0 -5 10 10")
      .attr("refX", 8)
      .attr("refY", 0)
      .attr("markerWidth", 6)
      .attr("markerHeight", 6)
      .attr("orient", "auto")
      .append("path")
      .attr("d", "M0,-5L10,0L0,5")
      .attr("fill", ac.color);
  });

  // Phase indicator
  const phaseGroup = svg.append("g")
    .attr("transform", `translate(${width/2}, 25)`);

  phaseGroup.append("text")
    .attr("text-anchor", "middle")
    .attr("fill", ieeeColors.orange)
    .attr("font-size", "18px")
    .attr("font-weight", "bold")
    .text(`Phase ${step + 1}: ${attack.steps[step].phase}`);

  // Step description
  svg.append("foreignObject")
    .attr("x", 20)
    .attr("y", height - 90)
    .attr("width", width - 40)
    .attr("height", 80)
    .append("xhtml:div")
    .style("background", "rgba(0,0,0,0.7)")
    .style("padding", "12px 16px")
    .style("border-radius", "8px")
    .style("border-left", `4px solid ${ieeeColors.orange}`)
    .html(`
      <div style="color: ${ieeeColors.white}; font-size: 14px; line-height: 1.5;">
        <strong>${attack.steps[step].description}</strong>
        ${protected ? `<br><span style="color: ${ieeeColors.green};">🛡️ Protection: Attack mitigated by security controls</span>` : ''}
      </div>
    `);

  return svg.node();
}

// Helper function for entity positions
function getEntityPositions(attackId, width, height) {
  const baseEntities = {
    mitm: [
      { type: "device", label: "IoT Device", x: 150, y: height/2 - 30, active: true, activeStep: 2 },
      { type: "attacker", label: "Attacker", x: width/2, y: height/2 - 30, active: true, activeStep: 1 },
      { type: "server", label: "Cloud Server", x: width - 150, y: height/2 - 30, active: true, activeStep: 2 },
      { type: "shield", label: "", x: width/2, y: height/2 - 30, active: true, activeStep: 0 }
    ],
    replay: [
      { type: "device", label: "Victim Device", x: 150, y: height/2 - 30, active: true, activeStep: 0 },
      { type: "attacker", label: "Attacker", x: width/2, y: height/2 + 80, active: true, activeStep: 1 },
      { type: "server", label: "Target Server", x: width - 150, y: height/2 - 30, active: true, activeStep: 3 },
      { type: "shield", label: "", x: width - 150, y: height/2 - 30, active: true, activeStep: 0 }
    ],
    dos: [
      { type: "device", label: "Botnet Device 1", x: 100, y: 120, active: true, activeStep: 2 },
      { type: "device", label: "Botnet Device 2", x: 100, y: height/2, active: true, activeStep: 2 },
      { type: "device", label: "Botnet Device 3", x: 100, y: height - 140, active: true, activeStep: 2 },
      { type: "attacker", label: "C&C Server", x: width/2, y: height/2, active: true, activeStep: 1 },
      { type: "server", label: "Target Server", x: width - 120, y: height/2, active: true, activeStep: 3 },
      { type: "shield", label: "", x: width - 120, y: height/2, active: true, activeStep: 0 }
    ],
    sidechannel: [
      { type: "device", label: "Target Device", x: width/2, y: height/2 - 30, active: true, activeStep: 1 },
      { type: "attacker", label: "Attacker + Probe", x: width/2 + 180, y: height/2 - 30, active: true, activeStep: 1 },
      { type: "shield", label: "", x: width/2, y: height/2 - 30, active: true, activeStep: 0 }
    ],
    firmware: [
      { type: "device", label: "Target Device", x: width/2, y: 150, active: true, activeStep: 0 },
      { type: "attacker", label: "Attacker", x: width/2, y: height - 150, active: true, activeStep: 1 },
      { type: "shield", label: "", x: width/2, y: 150, active: true, activeStep: 0 }
    ],
    downgrade: [
      { type: "device", label: "IoT Client", x: 150, y: height/2 - 30, active: true, activeStep: 0 },
      { type: "attacker", label: "Attacker", x: width/2, y: height/2 - 30, active: true, activeStep: 1 },
      { type: "server", label: "Server", x: width - 150, y: height/2 - 30, active: true, activeStep: 0 },
      { type: "shield", label: "", x: width/2, y: height/2 - 30, active: true, activeStep: 0 }
    ]
  };

  return baseEntities[attackId] || baseEntities.mitm;
}

// Helper function for attack flow visualization
function getAttackFlows(attackId, step, protected, entities, width, height) {
  const flows = {
    mitm: [
      { visible: step >= 0, path: `M 180 ${height/2-30} Q 300 ${height/2-100} ${width/2-30} ${height/2-30}`, label: "Normal Traffic", animated: true, malicious: false, blocked: false },
      { visible: step >= 1, path: `M ${width/2-30} ${height/2-30} Q 300 ${height/2+50} 180 ${height/2-30}`, label: "ARP Poison", animated: true, malicious: true, blocked: protected },
      { visible: step >= 2, path: `M ${width/2+30} ${height/2-30} Q 650 ${height/2-100} ${width-180} ${height/2-30}`, label: "Forwarded (intercepted)", animated: true, malicious: step >= 3, blocked: false },
      { visible: step >= 3, path: `M ${width/2} ${height/2+20} L ${width/2} ${height/2+80}`, label: "Extracted Data", animated: false, malicious: true, blocked: protected },
      { visible: step >= 4, path: `M ${width/2+30} ${height/2-30} Q 650 ${height/2+50} ${width-180} ${height/2-30}`, label: "Modified Data", animated: true, malicious: true, blocked: protected }
    ],
    replay: [
      { visible: step >= 0, path: `M 180 ${height/2-30} Q ${width/2} ${height/2-100} ${width-180} ${height/2-30}`, label: "Legitimate Message", animated: true, malicious: false, blocked: false },
      { visible: step >= 1, path: `M ${width/2} ${height/2-80} L ${width/2} ${height/2+30}`, label: "Capture", animated: false, malicious: true, blocked: false },
      { visible: step >= 2, path: `M ${width/2+30} ${height/2+80} L ${width/2+80} ${height/2+80}`, label: "Store", animated: false, malicious: true, blocked: false },
      { visible: step >= 3, path: `M ${width/2+30} ${height/2+80} Q ${width-200} ${height/2+60} ${width-180} ${height/2-30}`, label: "Replay", animated: true, malicious: true, blocked: protected },
      { visible: step >= 4, path: `M ${width-150} ${height/2+20} L ${width-150} ${height/2+60}`, label: protected ? "Rejected (nonce)" : "Accepted!", animated: false, malicious: !protected, blocked: false }
    ],
    dos: [
      { visible: step >= 2, path: `M 130 120 Q ${width/2+100} 100 ${width-150} ${height/2-50}`, label: "Flood", animated: true, malicious: true, blocked: protected },
      { visible: step >= 2, path: `M 130 ${height/2} L ${width-150} ${height/2}`, label: "Flood", animated: true, malicious: true, blocked: protected },
      { visible: step >= 2, path: `M 130 ${height-140} Q ${width/2+100} ${height-80} ${width-150} ${height/2+50}`, label: "Flood", animated: true, malicious: true, blocked: protected },
      { visible: step >= 1, path: `M ${width/2-30} ${height/2} L 130 ${height/2}`, label: "C&C", animated: true, malicious: true, blocked: false },
      { visible: step >= 1, path: `M ${width/2-30} ${height/2-30} Q 200 100 130 120`, label: "", animated: true, malicious: true, blocked: false },
      { visible: step >= 1, path: `M ${width/2-30} ${height/2+30} Q 200 ${height-100} 130 ${height-140}`, label: "", animated: true, malicious: true, blocked: false }
    ],
    sidechannel: [
      { visible: step >= 1, path: `M ${width/2+50} ${height/2-50} C ${width/2+100} ${height/2-100} ${width/2+150} ${height/2-80} ${width/2+150} ${height/2-50}`, label: "EM Emissions", animated: true, malicious: false, blocked: false },
      { visible: step >= 2, path: `M ${width/2+30} ${height/2} L ${width/2+150} ${height/2}`, label: "Power Trace", animated: true, malicious: false, blocked: protected },
      { visible: step >= 3, path: `M ${width/2+30} ${height/2+30} C ${width/2+100} ${height/2+80} ${width/2+150} ${height/2+60} ${width/2+150} ${height/2+30}`, label: "Timing Data", animated: true, malicious: false, blocked: protected },
      { visible: step >= 4, path: `M ${width/2+210} ${height/2-30} L ${width/2+280} ${height/2-30}`, label: protected ? "Noise Mask" : "Key Extracted!", animated: false, malicious: !protected, blocked: false }
    ],
    firmware: [
      { visible: step >= 1, path: `M ${width/2} 200 L ${width/2} ${height-200}`, label: "UART/JTAG Access", animated: false, malicious: true, blocked: protected },
      { visible: step >= 2, path: `M ${width/2-40} 170 Q ${width/2-100} ${height/2} ${width/2-40} ${height-170}`, label: "Memory Dump", animated: true, malicious: true, blocked: protected },
      { visible: step >= 3, path: `M ${width/2+40} ${height-170} Q ${width/2+100} ${height/2} ${width/2+40} 170`, label: "Analysis", animated: true, malicious: true, blocked: false },
      { visible: step >= 4, path: `M ${width/2} ${height-100} L ${width/2} ${height-60}`, label: protected ? "Encrypted" : "Secrets Found!", animated: false, malicious: !protected, blocked: false }
    ],
    downgrade: [
      { visible: step >= 0, path: `M 180 ${height/2-50} Q ${width/2} ${height/2-120} ${width-180} ${height/2-50}`, label: "TLS 1.3 Hello", animated: true, malicious: false, blocked: false },
      { visible: step >= 1, path: `M ${width-180} ${height/2-30} Q ${width/2} ${height/2-80} ${width/2-30} ${height/2-30}`, label: "Intercept", animated: true, malicious: true, blocked: false },
      { visible: step >= 2, path: `M ${width/2+30} ${height/2-30} Q ${width-200} ${height/2-80} ${width-180} ${height/2-30}`, label: protected ? "TLS 1.3 (enforced)" : "SSL 3.0 (forced)", animated: true, malicious: !protected, blocked: protected },
      { visible: step >= 3, path: `M ${width/2} ${height/2+20} L ${width/2} ${height/2+80}`, label: protected ? "Blocked" : "Exploit Vuln", animated: false, malicious: true, blocked: protected },
      { visible: step >= 4, path: `M ${width/2-30} ${height/2+80} Q 300 ${height/2+100} 180 ${height/2+30}`, label: protected ? "" : "Decrypted!", animated: !protected, malicious: true, blocked: protected }
    ]
  };

  return flows[attackId] || flows.mitm;
}
```
ImportantOJS Syntax Error (line 324, column 9)The keyword ‘protected’ is reserved

1407.2.2 Animation Controls

1407.2.3 Step Details Panel


1407.3 Summary

This core visualization tool provides interactive animations for understanding six common IoT security attacks:

  1. Man-in-the-Middle (MITM) - Interception and manipulation of communications
  2. Replay Attack - Capturing and retransmitting legitimate messages
  3. Denial of Service (DoS) - Overwhelming targets with malicious traffic
  4. Side-Channel Attack - Extracting secrets via physical characteristics
  5. Firmware Extraction - Physical extraction and analysis of device firmware
  6. Protocol Downgrade - Forcing use of weaker, vulnerable protocols

Use the playback controls to step through each attack phase and toggle protection mode to see how security controls mitigate threats.

1407.4 What’s Next

Continue learning about attack mitigation and defense strategies: