new(rules): detect GPU/accelerator cryptojacking and device access (T1496) - #373
new(rules): detect GPU/accelerator cryptojacking and device access (T1496)#373DevamShah wants to merge 1 commit into
Conversation
…1496) Add three maturity_sandbox artifacts to falco-sandbox_rules.yaml that detect GPU/accelerator cryptojacking, closing a gap the existing CPU/network-centric cryptominer rules do not cover: - list gpu_device_files + macro open_gpu_device + rule "Container Accessing GPU Device" (disabled by default): flags a container opening an NVIDIA/AMD compute device (/dev/nvidia*, /dev/nvidiactl, /dev/nvidia-uvm, /dev/kfd, /dev/dri/renderD*). The device open is the chokepoint a GPU miner cannot avoid even when it renames its binary and hides its pool traffic. - list gpu_management_binaries + rule "GPU Management Tool Run in Container": flags nvidia-smi/rocm-smi and friends running in a non-allowlisted container, a common pre-mining reconnaissance step. - macro user_known_gpu_workloads (never_true) as the documented tuning hook. Conventions mirror the sibling T1496 rules and the existing "Privileged Container Device Access" rule, which uses the same (open_read or open_write) + fd.name device-prefix pattern. Priority CRITICAL to match sibling T1496 rules; output uses the established bare key=%val template. Signed-off-by: Devam Shah <devamshah91@gmail.com>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: DevamShah The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Welcome @DevamShah! It looks like this is your first PR to falcosecurity/rules 🎉 |
leogr
left a comment
There was a problem hiding this comment.
Reviewed with https://github.com/leogr/falco-expert
| # by an ML/HPC workload; suspicious when spawned inside a workload that has no | ||
| # business touching the accelerator (e.g. a web frontend or a sidecar). | ||
| - list: gpu_management_binaries | ||
| items: [nvidia-smi, nvidia-debugdump, nvidia-persistenced, nvidia-cuda-mps-control, rocm-smi, rocminfo] |
There was a problem hiding this comment.
| items: [nvidia-smi, nvidia-debugdump, nvidia-persistenced, nvidia-cuda-mps-control, rocm-smi, rocminfo] | |
| items: [nvidia-smi, nvidia-debugdum, nvidia-persiste, nvidia-cuda-mps, rocm-smi, rocminfo] |
proc.name is the kernel task->comm, which is a char comm[16], so 15 usable chars plus the NUL. Three of the six entries are longer than that and can never match:
nvidia-debugdump- 16nvidia-persistenced- 19nvidia-cuda-mps-control- 23
nvidia-smi, rocm-smi and rocminfo are fine. So as written the rule silently covers half of the list. Since it is a false negative rather than a false positive, it is the kind of thing that goes unnoticed for a long time.
The suggestion truncates them to their comm form, which is what we already do elsewhere: falco_rules.yaml:585 lists nvidia-installe (i.e., the 16-char nvidia-installer), and :588 has unicorn_launche.
If you prefer to keep the names readable, the alternative is matching on proc.exepath endswith /nvidia-persistenced and friends, since proc.exepath is not truncated and is already in the output template. Either way is fine by me.
| and container | ||
| and not user_known_gpu_workloads | ||
| enabled: false | ||
| output: Container accessing GPU device | device=%fd.name image=%container.image.repository evt_type=%evt.type user=%user.name user_uid=%user.uid user_loginuid=%user.loginuid process=%proc.name proc_exepath=%proc.exepath parent=%proc.pname command=%proc.cmdline terminal=%proc.tty |
There was a problem hiding this comment.
| output: Container accessing GPU device | device=%fd.name image=%container.image.repository evt_type=%evt.type user=%user.name user_uid=%user.uid user_loginuid=%user.loginuid process=%proc.name proc_exepath=%proc.exepath parent=%proc.pname command=%proc.cmdline terminal=%proc.tty | |
| output: Container accessing GPU device | device=%fd.name evt_type=%evt.type user=%user.name user_uid=%user.uid user_loginuid=%user.loginuid process=%proc.name proc_exepath=%proc.exepath parent=%proc.pname command=%proc.cmdline terminal=%proc.tty |
Dropping image=%container.image.repository for consistency.
No rule in the tree carries container identity fields in its output. Across the three rule files the only %container.* uses are %container.mounts in Container with sensitive mount started and %container.start_ts in two falco_rules.yaml rules, and in both cases the field is what the rule is actually about.
The style guide asks to keep upstream outputs minimal and to leave ID-style fields to the customization phase 👉 https://falco.org/docs/rules/style-guide/#output-fields
Operators get container metadata downstream anyway, either through append_output (suggested_output: true) or the -pc option.
Also worth noting that the sibling Privileged Container Device Access rule, which this one mirrors, uses exactly device=%fd.name evt_type=... with no image field.
| priority: CRITICAL | ||
| tags: [maturity_sandbox, container, filesystem, mitre_impact, T1496] | ||
|
|
||
| - rule: GPU Management Tool Run in Container |
There was a problem hiding this comment.
Both rules gate on user_known_gpu_workloads, which ships as (never_true), but only the device-access rule ships enabled: false. Was that deliberate? 🤔
I do not have a good feeling for how often nvidia-smi runs legitimately inside containers in GPU fleets, so I may well be wrong here. However, if the reason for disabling the first rule is "noisy until the macro is tuned", the same seems to apply to this one, since it depends on the very same untuned macro.
wdyt?
| and container | ||
| and proc.name in (gpu_management_binaries) | ||
| and not user_known_gpu_workloads | ||
| output: GPU management tool run in container | image=%container.image.repository evt_type=%evt.type user=%user.name user_uid=%user.uid user_loginuid=%user.loginuid process=%proc.name proc_exepath=%proc.exepath parent=%proc.pname command=%proc.cmdline terminal=%proc.tty exe_flags=%evt.arg.flags |
There was a problem hiding this comment.
| output: GPU management tool run in container | image=%container.image.repository evt_type=%evt.type user=%user.name user_uid=%user.uid user_loginuid=%user.loginuid process=%proc.name proc_exepath=%proc.exepath parent=%proc.pname command=%proc.cmdline terminal=%proc.tty exe_flags=%evt.arg.flags | |
| output: GPU management tool run in container | evt_type=%evt.type user=%user.name user_uid=%user.uid user_loginuid=%user.loginuid process=%proc.name proc_exepath=%proc.exepath parent=%proc.pname command=%proc.cmdline terminal=%proc.tty exe_flags=%evt.arg.flags |
Same here.
/kind feature
/area rules
/area maturity-sandbox
What type of PR is this?
Any specific area of the project related to this PR?
What this PR does / why we need it
Adds three
maturity_sandboxartifacts torules/falco-sandbox_rules.yamlthat detect GPU/accelerator cryptojacking — a container opening an NVIDIA/AMD compute device, and GPU management tooling (nvidia-smi,rocm-smi) running inside a container — closing a coverage gap the existing CPU/network-centric cryptominer rules do not address.Problem / motivation
Falco's current cryptominer coverage in
falco-sandbox_rules.yamlis CPU- and network-centric:proc.cmdlineforstratum+tcp/stratum+ssl.xmrig,ethminer, ...).All three are trivially evaded by a GPU miner. An attacker who has compromised a GPU-equipped node (common in ML/AI and rendering fleets, where idle accelerator capacity is a high-value cryptojacking target) can use a renamed or custom miner binary, connect over an encrypted/proxied channel to an unknown pool, and avoid the
stratumURI scheme entirely.What the miner cannot avoid is opening a GPU character device to submit work to the hardware (
/dev/nvidia*,/dev/nvidiactl,/dev/nvidia-uvmfor CUDA;/dev/kfdand/dev/dri/renderD*for AMD ROCm). That device open is the chokepoint this PR instruments. This is GPU compute, distinct from the existing Privileged Container Device Access rule, which targets raw block/storage devices (/dev/sd,/dev/nvme,/dev/mem) for container escape (T1611) — no overlap with GPU compute devices.Change
list: gpu_device_files—/dev/nvidiactl,/dev/nvidia-uvm,/dev/nvidia-uvm-tools,/dev/kfd.macro: open_gpu_device— anopen_read/open_writeon agpu_device_filesentry, any/dev/nvidia*per-GPU node, or a/dev/dri/renderD*DRM render node.list: gpu_management_binaries—nvidia-smi,nvidia-debugdump,nvidia-persistenced,nvidia-cuda-mps-control,rocm-smi,rocminfo.macro: user_known_gpu_workloads(defaults tonever_true) — the documented tuning hook for clusters with legitimate ML/HPC/rendering workloads, overridable by image (e.g.container.image.repository in (my_ml_images)).rule: Container Accessing GPU Device(priorityCRITICAL, disabled by default) — behavioral signal: a container opens a GPU compute device and is not an allowlisted workload. Shipped disabled because it is noisy untiluser_known_gpu_workloadsis tuned to the images expected to use the GPU.rule: GPU Management Tool Run in Container(priorityCRITICAL) — signature signal: GPU fingerprinting tooling runs in a non-allowlisted container.Conventions mirror the adjacent rules: first tag is the maturity level (
maturity_sandbox);containerscope, killchain phase (mitre_impact) and TTP (T1496) tags match the sibling stratum and miner-binary rules; both rules use anever_true-backeduser_known_*tuning macro and the establishedevt_type / user / process / proc_exepath / parent / command / terminaloutput template. The device-open rule deliberately reuses the exact(open_read or open_write) and container and fd.name startswith /dev/...pattern already used by the existing Privileged Container Device Access rule in this same file.Security rationale
user_known_gpu_workloadstuning macro. The behavioral rule shipsenabled: falseper repo precedent for noisy-by-default rules.Testing / validation
falco --validate rules/falco-sandbox_rules.yamlinfalcosecurity/falco:0.44.1→Ok.modern_ebpfdriver and the rule temporarily enabled, then opened character-device nodes at the matched paths inside a separate container:Container Accessing GPU Devicefired CRITICAL oncat /dev/nvidia0andhead -c1 /dev/nvidiactlfrom abusyboxcontainer:Critical Container accessing GPU device | device=/dev/nvidia0 image=busybox evt_type=openat ... process=cat ... container_name=gpu-trigger2GPU Management Tool Run in Containerfired CRITICAL on executingnvidia-smiinside a container:Critical GPU management tool run in container | image=busybox evt_type=execve process=nvidia-smi ...open_read/open_writemacros (fd.typechar='f',fd.num>=0) do match successful character-device opens, exactly as the sibling block-device rule relies on.Special notes for your reviewer
Submitted as
maturity_sandboxper the maturity framework — an experimental detection that pairs a behavioral and a signature signal. Happy to split the two rules, adjust the device/management-binary lists, or change the default-enabled state based on maintainer preference.