{
  "technique_id": "T1052",
  "name": "Exfiltration Over Physical Medium",
  "priority": "high",
  "status": "draft",
  "version": "0.1.0",
  "last_reviewed": "2026-07-23",
  "generated_by": "SOC Response Atlas by Basyrix",
  "tactics": [
    "Exfiltration"
  ],
  "platforms": [
    "Linux",
    "macOS",
    "Windows"
  ],
  "summary": "Adversaries may attempt to exfiltrate data via a physical medium, such as a removable drive. In certain circumstances, such as an air-gapped network compromise, exfiltration could occur via a physical medium or device introduced by a user. Such media could be an external hard drive, USB drive, cellular phone, MP3 player, or other removable storage and processing device. The physical medium or device could be used as the final exfiltration point or to hop between otherwise disconnected systems.",
  "soc_recommendation": "Investigate Exfiltration Over Physical Medium activity in the context of Exfiltration: confirm scope, affected host/identity, and whether it matches expected administrative behaviour before deciding this is benign.",
  "d3fend_mappings": [
    {
      "id": "D3-RH",
      "name": "Radiation Hardening",
      "relationship": "harden",
      "practical_action": "Apply Radiation Hardening to reduce this technique's viability before an incident occurs.",
      "tooling": [
        "Defender for Endpoint"
      ]
    },
    {
      "id": "D3-IOPR",
      "name": "IO Port Restriction",
      "relationship": "isolate",
      "practical_action": "Apply IO Port Restriction to contain the blast radius once this technique is observed.",
      "tooling": [
        "Defender for Endpoint"
      ]
    },
    {
      "id": "D3-HCI",
      "name": "Hardware Component Inventory",
      "relationship": "model",
      "practical_action": "Use Hardware Component Inventory to establish a baseline that makes this technique's deviations easier to spot.",
      "tooling": [
        "Defender for Endpoint"
      ]
    }
  ],
  "investigation_steps": {
    "microsoft": [
      "Review Defender for Endpoint / Defender XDR alerts and timeline for the affected host or identity.",
      "Check Sentinel analytics rules and incidents correlated with this technique.",
      "Review Entra ID sign-in and audit logs if the technique involves an identity or cloud resource."
    ],
    "generic": [
      "Confirm whether the observed exfiltration over physical medium activity matches expected administrative or application behaviour.",
      "Identify the host, account, or resource where the activity occurred and its business criticality.",
      "Check for related alerts before and after this activity to reconstruct the broader intrusion timeline.",
      "Real detection reference: \"Dataverse - Terminated employee exfiltration to USB drive\" -- Identifies files downloaded from Dataverse by departing or terminated employees which are copied to USB mounted drives."
    ]
  },
  "evidence_to_collect": [
    "Host or resource affected",
    "Account or identity involved",
    "Timestamp of the activity",
    "Related process, file, or network artifact",
    "Any preceding or follow-on alerts"
  ],
  "response_actions": [
    {
      "name": "Contain the affected host or account",
      "category": "Containment",
      "risk": "Medium",
      "automation_safe": false,
      "approval_required": true,
      "tool": "Defender for Endpoint / Entra ID",
      "notes": "Requires approval -- confirm malicious intent before isolating a host or disabling an account."
    },
    {
      "name": "Collect and preserve evidence",
      "category": "Investigation",
      "risk": "Low",
      "automation_safe": true,
      "approval_required": false,
      "tool": "Defender for Endpoint",
      "notes": "Safe -- read-only evidence collection."
    }
  ],
  "queries": {
    "kql": [
      {
        "name": "c5e75cb6-cea0-49c2-a998-da414035aac1 — Dataverse - Terminated employee exfiltration to USB drive",
        "description": "Identifies files downloaded from Dataverse by departing or terminated employees which are copied to USB mounted drives. (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed).)",
        "query": "let drive_mount_lookback = 14d;\nlet query_frequency = 1h;\nDataverseActivity\n| distinct InstanceUrl\n| join kind=inner (DeviceFileEvents\n    | where TimeGenerated >= ago(query_frequency))\n    on $left.InstanceUrl == $right.FileOriginUrl\n| join kind=inner (MSBizAppsTerminatedEmployees()) on $left.InitiatingProcessAccountUpn == $right.UserPrincipalName\n| join kind=inner (DeviceEvents\n    | where TimeGenerated >= ago(drive_mount_lookback)\n    | where ActionType == \"UsbDriveMounted\"\n    | extend DriveLetter = tostring(AdditionalFields.DriveLetter)\n    | summarize MountedDriveLetters = make_set(DriveLetter, 26) by DeviceId, DeviceName)\n    on DeviceId\n| extend TargetDriveLetter = tostring(split(FolderPath, \"\\\\\")[0])\n| where set_has_element(MountedDriveLetters, TargetDriveLetter)\n| join kind=inner (DeviceInfo\n    | summarize arg_max(TimeGenerated, DeviceId, PublicIP) by DeviceName)\n    on DeviceId\n| project-rename\n    UserId = UserPrincipalName\n| summarize LatestEvent = arg_max(TimeGenerated, *), Files = make_set(FileName, 100) by UserId, InstanceUrl\n| extend\n    CloudAppId = int(32780),\n    AccountName = tostring(split(UserId, '@')[0]),\n    UPNSuffix = tostring(split(UserId, '@')[1])\n| project\n    LatestEvent,\n    UserId,\n    PublicIP,\n    Files,\n    InstanceUrl,\n    CloudAppId,\n    AccountName,\n    UPNSuffix"
      },
      {
        "name": "6267ce44-1e9d-471b-9f1e-ae76a6b7aa84 — Mass Download & copy to USB device by single user",
        "description": "This query looks for any mass download by a single user with possible file copy activity to a new USB drive. Malicious insiders may perform such activities that may cause harm to the organization. This query could also reveal unintentional insider that had no intention of malicious activity but their actions may impact an organizations security posture. Reference:https://docs.microsoft.com/defender-cloud-apps/policy-template-reference' (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed).)",
        "query": "let Alerts = SecurityAlert\n| where AlertName =~ \"mass download by a single user\"\n| where Status != 'Resolved'\n| extend ipEnt = parse_json(Entities), accountEnt = parse_json(Entities)\n| mv-apply tempParams = ipEnt on (\nmv-expand ipEnt\n| where ipEnt.Type == \"ip\" \n| extend IpAddress = tostring(ipEnt.Address)\n)\n| mv-apply tempParams = accountEnt on (\nmv-expand accountEnt\n| where accountEnt.Type == \"account\"\n| extend AADUserId = tostring(accountEnt.AadUserId)\n)\n| extend Alert_TimeGenerated = TimeGenerated\n| distinct Alert_TimeGenerated, IpAddress, AADUserId, DisplayName, Description, ProductName, ExtendedProperties, Entities, Status, CompromisedEntity\n;\nlet CA_Events = CloudAppEvents\n| where ActionType == \"FileDownloaded\"\n| extend parsed = parse_json(RawEventData)\n| extend UserId = tostring(parsed.UserId)\n| extend FileName = tostring(parsed.SourceFileName)\n| extend FileExtension = tostring(parsed.SourceFileExtension)\n| summarize CloudAppEvent_StartTime = min(TimeGenerated), CloudAppEvent_EndTime = max(TimeGenerated), CloudAppEvent_Files = make_set(FileName), FileCount = dcount(FileName) by Application, AccountObjectId, UserId, IPAddress, City, CountryCode\n| extend CloudAppEvents_Details = pack_all();\nlet CA_Alerts_Events = Alerts | join kind=inner (CA_Events)\non $left.AADUserId == $right.AccountObjectId and $left.IpAddress == $right.IPAddress\n// Cloud app event comes before Alert\n| where CloudAppEvent_EndTime <= Alert_TimeGenerated\n| project Alert_TimeGenerated, UserId, AADUserId, IPAddress, CloudAppEvents_Details, CloudAppEvent_Files\n;\n// setup list to filter DeviceFileEvents for only files downloaded as indicated by CloudAppEvents\nlet CA_FileList = CA_Alerts_Events | project CloudAppEvent_Files;\nCA_Alerts_Events\n| join kind=inner ( DeviceFileEvents\n| where ActionType in (\"FileCreated\", \"FileRenamed\")\n| where FileName in~ (CA_FileList)\n| summarize DeviceFileEvent_StartTime = min(TimeGenerated), DeviceFileEvent_EndTime = max(TimeGenerated), DeviceFileEvent_Files = make_set(FolderPath), DeviceFileEvent_FileCount = dcount(FolderPath) by InitiatingProcessAccountUpn, DeviceId, DeviceName, InitiatingProcessFolderPath, InitiatingProcessParentFileName//, InitiatingProcessCommandLine\n| extend DeviceFileEvents_Details = pack_all()\n) on $left.UserId == $right.InitiatingProcessAccountUpn\n| where DeviceFileEvent_StartTime >= Alert_TimeGenerated\n| join kind=inner (\n// get device events where a USB drive was mounted\nDeviceEvents\n| where ActionType == \"UsbDriveMounted\"\n| extend parsed = parse_json(AdditionalFields)\n| extend USB_DriveLetter = tostring(AdditionalFields.DriveLetter), USB_ProductName = tostring(AdditionalFields.ProductName), USB_Volume = tostring(AdditionalFields.Volume)\n| where isnotempty(USB_DriveLetter)\n| project USB_TimeGenerated = TimeGenerated, DeviceId, USB_DriveLetter, USB_ProductName, USB_Volume\n| extend USB_Details = pack_all()\n)  \non DeviceId\n// USB event occurs after the Alert\n| where USB_TimeGenerated >= Alert_TimeGenerated\n| mv-expand DeviceFileEvent_Files\n| extend DeviceFileEvent_Files = tostring(DeviceFileEvent_Files)\n// make sure that we only pickup the files that have the USB drive letter\n| where DeviceFileEvent_Files startswith USB_DriveLetter\n| summarize USB_Drive_MatchedFiles = make_set_if(DeviceFileEvent_Files, DeviceFileEvent_Files startswith USB_DriveLetter) by Alert_TimeGenerated, USB_TimeGenerated, UserId, AADUserId, DeviceId, DeviceName, IPAddress, CloudAppEvents_Details = tostring(CloudAppEvents_Details), DeviceFileEvents_Details = tostring(DeviceFileEvents_Details), USB_Details = tostring(USB_Details)\n| extend InitiatingProcessFileName = tostring(split(todynamic(DeviceFileEvents_Details).InitiatingProcessFolderPath, \"\\\\\")[-1]), InitiatingProcessFolderPath = tostring(todynamic(DeviceFileEvents_Details).InitiatingProcessFolderPath)\n| extend HostName = tostring(split(DeviceName, \".\")[0]), DomainIndex = toint(indexof(DeviceName, '.'))\n| extend HostNameDomain = iff(DeviceName != -1, substring(DeviceName, DomainIndex + 1), DeviceName)\n| extend AccountName = tostring(split(UserId, \"@\")[0]), AccountUPNSuffix = tostring(split(UserId, \"@\")[1])\n| project-away DomainIndex"
      }
    ],
    "spl": [],
    "esql": [
      {
        "name": "483832a8-ffdd-4e11-8e96-e0224f7bda9b — New USB Storage Device Mounted",
        "description": "(KUERY) Identifies newly seen removable devices by device.serial_number and host.id using the Elastic Defend device mount events. While this activity is not inherently malicious, analysts can use those events to aid monitoring for data exfiltration over those devices. (Source: Elastic's official detection-rules repository (Elastic License v2).)",
        "query": "host.os.type:(macos or windows) and event.type:device and event.action:mount and event.outcome:success and volume.removable:true"
      },
      {
        "name": "0859355c-0f08-4b43-8ff5-7d2a4789fc08 — First Time Seen Removable Device",
        "description": "(KUERY) Identifies newly seen removable devices by device friendly name using registry modification events. While this activity is not inherently malicious, analysts can use those events to aid monitoring for data exfiltration over those devices. (Source: Elastic's official detection-rules repository (Elastic License v2).)",
        "query": "event.category:\"registry\" and host.os.type:\"windows\" and registry.value:\"FriendlyName\" and registry.path:*USBSTOR*"
      }
    ]
  },
  "automation": {
    "safe": [
      "Add recommendation as Sentinel incident comment.",
      "Run enrichment queries.",
      "Create ServiceNow SecOps task."
    ],
    "approval_required": [
      "Contain or disable the affected host/account.",
      "Any change to production configuration."
    ]
  },
  "escalation_criteria": [
    "Exfiltration Over Physical Medium activity observed on a privileged account or critical system.",
    "Activity follows or precedes other suspicious behaviour in the same investigation.",
    "Automated triage cannot confidently rule out malicious intent."
  ],
  "false_positive_considerations": [
    "Legitimate administrative or maintenance activity matching this pattern.",
    "Approved security testing or red team exercise.",
    "Known benign software producing similar telemetry."
  ],
  "confluence": {
    "title": "T1052 - Exfiltration Over Physical Medium Response Guidance",
    "labels": [
      "mitre",
      "attack",
      "d3fend",
      "secops",
      "basyrix"
    ],
    "sections": [
      "summary",
      "d3fend_mappings",
      "investigation_steps",
      "response_actions",
      "queries",
      "automation",
      "escalation_criteria",
      "false_positive_considerations"
    ]
  }
}