Container Service
Adversaries may create or modify container or container cluster management tools that run as daemons, agents, or services on individual hosts. These include software for creating and managing individual containers, such as Docker and Podman, as well as container cluster node-level agents such as kubelet. By modifying these services, an adversary may achieve persistence or escalate their privileges on a host. Common abuse patterns include using 'docker run' or 'podman run' with the '--restart=always' directive to configure a container to persistently restart after daemon restarts or host reboots, using '--privileged', '--pid=host', or '--net=host' flags to break container isolation and gain access to the underlying host kernel, bind-mounting the root filesystem ('-v /:/') to read or modify host files, and leveraging Kubernetes DaemonSets to deploy malicious containers persistently across all current and future cluster nodes. Threat actor groups including TeamTNT have exploited exposed Docker APIs to deploy cryptomining and backdoor containers with restart=always policies. Privilege escalation via docker group membership is documented in GTFOBins and widely exploited in post-exploitation scenarios.
let SuspiciousContainerFlags = dynamic([
"--restart=always", "--restart always",
"--privileged",
"--pid=host",
"--net=host", "--network=host",
"--cap-add=SYS_ADMIN", "--cap-add SYS_ADMIN",
"--cap-add ALL", "--cap-add=ALL",
"-v /:/", "--volume /:/",
"--device /dev/mem", "--device /dev/kmem"
]);
let ContainerRuntimes = dynamic(["docker", "podman", "nerdctl"]);
// Signal 1: Container run with persistence (restart=always) or privilege escalation flags
let ContainerRunAbuse = DeviceProcessEvents
| where Timestamp > ago(24h)
| where (FileName in~ (ContainerRuntimes)) or (InitiatingProcessFileName in~ (ContainerRuntimes))
| where ProcessCommandLine has "run"
| where ProcessCommandLine has_any (SuspiciousContainerFlags)
| extend PersistenceFlag = ProcessCommandLine has_any ("--restart=always", "--restart always")
| extend PrivilegedFlag = ProcessCommandLine has_any ("--privileged", "--pid=host", "--net=host", "--network=host", "--cap-add=SYS_ADMIN", "--cap-add SYS_ADMIN", "--cap-add ALL", "--cap-add=ALL")
| extend HostMountFlag = ProcessCommandLine has_any ("-v /:/", "--volume /:/", "--device /dev/mem", "--device /dev/kmem")
| extend RiskScore = toint(PersistenceFlag) + toint(PrivilegedFlag) + toint(HostMountFlag)
| extend AttackPattern = case(
PersistenceFlag and PrivilegedFlag, "CRITICAL: Persistent privileged container — auto-restart with full host kernel access",
PersistenceFlag and HostMountFlag, "CRITICAL: Persistent container with host root filesystem mount",
PrivilegedFlag and HostMountFlag, "HIGH: Privileged container with host root filesystem access",
PersistenceFlag, "MEDIUM: Container persistence via restart=always policy",
PrivilegedFlag, "HIGH: Container privilege escalation or host escape via capability flags",
HostMountFlag, "HIGH: Host root filesystem bind mount — full host file read/write",
"MEDIUM: Suspicious container configuration"
)
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
InitiatingProcessFileName, InitiatingProcessCommandLine,
PersistenceFlag, PrivilegedFlag, HostMountFlag, RiskScore, AttackPattern;
// Signal 2: Docker exec spawning interactive shell (post-exploitation inside container)
let ContainerExecShell = DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName in~ (ContainerRuntimes)
| where ProcessCommandLine has "exec"
| where ProcessCommandLine has_any ("/bin/bash", "/bin/sh", "/bin/zsh", "bash", "sh -i", "sh -c")
| where not(InitiatingProcessFileName in~ ("containerd", "dockerd", "container-shim"))
| extend PersistenceFlag = false
| extend PrivilegedFlag = false
| extend HostMountFlag = false
| extend RiskScore = 1
| extend AttackPattern = "MEDIUM: Interactive shell exec into running container — potential lateral movement or post-exploitation"
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
InitiatingProcessFileName, InitiatingProcessCommandLine,
PersistenceFlag, PrivilegedFlag, HostMountFlag, RiskScore, AttackPattern;
ContainerRunAbuse
| union ContainerExecShell
| sort by Timestamp desc Data Sources
Required Tables
False Positives
- Legitimate infrastructure-as-code pipelines (Ansible, Terraform, Puppet) deploying containers with specific restart policies in staging and production environments
- Platform engineering teams running privileged containers for system-level tooling such as monitoring exporters (node-exporter, Falco), network packet capture tools, or kernel debuggers
- Container security tooling (Falco, Sysdig, Tetragon) that require --privileged or specific capabilities to instrument the kernel
- Developers using 'docker exec' to debug running containers in development environments
- CI/CD systems running Docker-in-Docker (DinD) builds that require privileged containers or socket mounts
References (12)
- https://attack.mitre.org/techniques/T1543/005/
- https://blog.aquasec.com/teamtnt-reemerged-with-new-aggressive-cloud-campaign
- https://blog.aquasec.com/leveraging-kubernetes-rbac-to-backdoor-clusters
- https://gtfobins.github.io/gtfobins/docker/
- https://docs.docker.com/config/containers/start-containers-automatically/
- https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/
- https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/
- https://blog.appsecco.com/kubernetes-namespace-breakout-using-insecure-host-path-volume-part-1-b382f2a6e216
- https://www.redhat.com/sysadmin/podman-run-pods-systemd-services
- https://falco.org/docs/rules/default-macros/
- https://learn.microsoft.com/en-us/azure/aks/monitor-aks
- https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1543.005/T1543.005.md
Unlock Pro Content
Get the full detection package for T1543.005 including response playbook, investigation guide, and atomic red team tests.