T1612 Microsoft Sentinel · KQL

Detect Build Image on Host in Microsoft Sentinel

This detection identifies adversaries building custom container images directly on a compromised host to evade registry-based defenses. Rather than pulling a pre-built malicious image — which would trigger image scanning alerts — attackers issue docker build commands referencing Dockerfiles that download malware or backdoors at build time using RUN curl/wget instructions. The detection monitors for docker build process execution with suspicious argument patterns (temporary directory Dockerfiles, no-cache flags, external URL fetches), Dockerfile creation in writable system directories, and Docker daemon network connections to unexpected destinations during image construction. Correlation across process telemetry, file events, and network activity surfaces the build-then-deploy attack chain used by groups like TeamTNT and WatchDog cryptomining campaigns.

MITRE ATT&CK

Tactic
Defense Evasion
Technique
T1612 Build Image on Host
Canonical reference
https://attack.mitre.org/techniques/T1612/

KQL Detection Query

Microsoft Sentinel (KQL)
kusto
let TimeWindow = 1d;
let TempPaths = dynamic(["/tmp/", "/dev/shm/", "/var/tmp/", "/run/user/", "\\Temp\\", "\\AppData\\Local\\Temp\\"]);
let SuspiciousParents = dynamic(["bash", "sh", "zsh", "python", "python3", "perl", "ruby", "curl", "wget"]);
// Detect suspicious docker build executions
let DockerBuilds = DeviceProcessEvents
| where TimeGenerated > ago(TimeWindow)
| where (FileName =~ "docker" or FileName =~ "docker.exe")
    and ProcessCommandLine has_any ("build", "image build")
| extend BuildFromTemp = ProcessCommandLine has_any (TempPaths)
| extend BuildNoCache = ProcessCommandLine has "--no-cache"
| extend BuildExternalFile = ProcessCommandLine matches regex @"-f\s+https?://"
| extend SuspiciousParentProc = InitiatingProcessFileName has_any (SuspiciousParents)
| extend RiskScore = toint(BuildFromTemp) * 3
    + toint(BuildNoCache) * 1
    + toint(BuildExternalFile) * 4
    + toint(SuspiciousParentProc) * 2
| where RiskScore >= 2
| project TimeGenerated, DeviceName, AccountName, AccountDomain,
          ProcessCommandLine, InitiatingProcessCommandLine, InitiatingProcessFileName,
          BuildFromTemp, BuildNoCache, BuildExternalFile, SuspiciousParentProc, RiskScore;
// Detect Dockerfile written to suspicious locations
let SuspiciousDockerfiles = DeviceFileEvents
| where TimeGenerated > ago(TimeWindow)
| where (FileName =~ "Dockerfile" or FileName endswith ".dockerfile" or FileName endswith ".Dockerfile")
    and FolderPath has_any (TempPaths)
| extend RiskScore = 3
| project TimeGenerated, DeviceName, AccountName, FolderPath, FileName,
          InitiatingProcessCommandLine, RiskScore;
// Detect docker daemon making external connections during potential build phase
let DockerNetworkBuild = DeviceNetworkEvents
| where TimeGenerated > ago(TimeWindow)
| where InitiatingProcessFileName =~ "dockerd"
    and RemotePort in (80, 443, 8080, 8443)
    and not(ipv4_is_private(RemoteIP))
    and not(RemoteUrl has_any ("docker.io", "hub.docker.com", "registry-1.docker.io",
                               "production.cloudflare.docker.com", "auth.docker.io",
                               "registry.k8s.io", "gcr.io", "mcr.microsoft.com",
                               "quay.io", "ghcr.io"))
| extend RiskScore = 2
| project TimeGenerated, DeviceName, RemoteIP, RemoteUrl, RemotePort,
          InitiatingProcessCommandLine, RiskScore;
// Union all findings
DockerBuilds
| project TimeGenerated, DeviceName, AccountName, Description = "Suspicious docker build execution",
          Detail = ProcessCommandLine, RiskScore
| union (
    SuspiciousDockerfiles
    | project TimeGenerated, DeviceName, AccountName, Description = "Dockerfile written to temp path",
              Detail = strcat(FolderPath, FileName), RiskScore
)
| union (
    DockerNetworkBuild
    | project TimeGenerated, DeviceName, AccountName = "", Description = "Docker daemon external connection during build",
              Detail = strcat(RemoteIP, " (", RemoteUrl, "):", tostring(RemotePort)), RiskScore
)
| order by TimeGenerated desc
high severity medium confidence

Detects suspicious container image builds on the host by monitoring docker build process executions with high-risk argument patterns (Dockerfiles from temp directories, external file references, no-cache flags combined with suspicious parent processes), Dockerfile creation in writable system paths, and Docker daemon making network connections to non-registry external hosts during what may be a build phase. Risk scoring prioritizes combinations most consistent with adversary build-to-deploy workflows.

Data Sources

Microsoft Defender for Endpoint

Required Tables

DeviceProcessEventsDeviceFileEventsDeviceNetworkEvents

False Positives & Tuning

  • Legitimate CI/CD pipeline agents (Jenkins, GitLab Runner, GitHub Actions self-hosted) that build images on the host using --no-cache for reproducibility
  • Developer workstations with Docker Desktop where developers routinely build images from ~/Downloads or temp directories during testing
  • Container security scanning tools (Trivy, Grype, Snyk) that build test images from temporary Dockerfiles to verify vulnerability detection coverage
  • Infrastructure-as-code tools like Packer or Terraform using Docker builder that create Dockerfiles in temp locations as part of their workflow
Download portable Sigma rule (.yml)

Other platforms for T1612


Testing Methodology

Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1Build Custom Image with Embedded Payload Simulation

    Expected signal: DeviceProcessEvents: FileName=docker, ProcessCommandLine contains 'build --no-cache -t atomictest_t1612' and '/tmp/atomictest_t1612/Dockerfile'. DeviceNetworkEvents: dockerd process making connection to example.com:443 during RUN curl step.

  2. Test 2Docker API Remote Build Request Simulation

    Expected signal: Auditd: access to /var/run/docker.sock by curl process. Docker daemon logs (journalctl -u docker): POST /v1.43/build request logged. DeviceProcessEvents may not show docker CLI — hunting via socket access rules is required for API-based builds.

  3. Test 3Build Privileged Escape-Ready Container Image

    Expected signal: DeviceProcessEvents: docker run with ProcessCommandLine containing '-v /var/run/docker.sock:/var/run/docker.sock'. Sysmon EventCode 11: file access to /var/run/docker.sock from container process namespace.

Unlock Pro Content

Get the full detection package for T1612 including response playbook, investigation guide, and atomic red team tests.

Response PlaybookInvestigation GuideHunting QueriesAtomic Red Team TestsTuning Guidance

Related Detections