--- ############################################## # # rules a mostly a copy of standard falco rules # # https://github.com/falcosecurity/rules/tree/main/rules # # WARNING: DO NOT FORGET TO ADD REQUIRED TAGS: # - alg # - siem # - audit # - required_engine_version: 26 ############################################## # Required lists and macros for rules to work # - macro: never_true condition: (evt.num=0) - list: shell_binaries items: [ash, bash, csh, ksh, sh, tcsh, zsh, dash] - macro: shell_procs condition: (proc.name in (shell_binaries)) - macro: spawned_process condition: (evt.type in (execve, execveat) and evt.dir=<) - macro: container condition: (container.id != host) - macro: open_write condition: (evt.type in (open,openat,openat2) and evt.is_open_write=true and fd.typechar='f' and fd.num>=0) - macro: open_read condition: (evt.type in (open,openat,openat2) and evt.is_open_read=true and fd.typechar='f' and fd.num>=0) # The steps libcontainer performs to set up the root program for a container are: # - clone + exec self to a program runc:[0:PARENT] # - clone a program runc:[1:CHILD] which sets up all the namespaces # - clone a second program runc:[2:INIT] + exec to the root program. # The parent of runc:[2:INIT] is runc:0:PARENT] # As soon as 1:CHILD is created, 0:PARENT exits, so there's a race # where at the time 2:INIT execs the root program, 0:PARENT might have # already exited, or might still be around. So we handle both. # We also let runc:[1:CHILD] count as the parent process, which can occur # when we lose events and lose track of state. - macro: container_entrypoint condition: (not proc.pname exists or proc.pname in (runc:[0:PARENT], runc:[1:CHILD], runc, docker-runc, exe, docker-runc-cur, containerd-shim, systemd, crio)) - macro: kernel_module_load condition: (evt.type in (init_module, finit_module) and evt.dir=<) ###################################### # Custom rules # #################################################################### # Copy of the default falco rule, removed 'and not # user_expected_terminal_shell_in_container_conditions' from # condition, so whenever someone opens a shell in a container create # an event - rule: Terminal shell in container desc: > A shell was used as the entrypoint/exec point into a container with an attached terminal. Parent process may have legitimately already exited and be null (read container_entrypoint macro). Common when using "kubectl exec" in Kubernetes. Correlate with k8saudit exec logs if possible to find user or serviceaccount token used (fuzzy correlation by namespace and pod name). Rather than considering it a standalone rule, it may be best used as generic auditing rule while examining other triggered rules in this container/tty. condition: > spawned_process and container and shell_procs and proc.tty != 0 and container_entrypoint output: A shell was spawned in a container with an attached terminal (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 %container.info) priority: NOTICE tags: [maturity_stable, container, shell, mitre_execution, T1059, siem] ####################################################################### # Log all commands executed in an interactive shell inside a # container. This creates events for all processes created via execve # and execve. # # WARNING: this does not capture shell builtins. See the next rule for # a possible mitigation. - rule: Log commands in an interactive shell desc: >- Log all commands executed in a container that has a tty attached. Taken from https://github.com/falcosecurity/falco/issues/2338#issuecomment-1631308628. condition: >- spawned_process and container and proc.tty != 0 and proc.is_vpgid_leader=true output: Executed command in container (proc_exe=%proc.exe proc_sname=%proc.sname gparent=%proc.aname[2] proc_exe_ino_ctime=%proc.exe_ino.ctime proc_exe_ino_mtime=%proc.exe_ino.mtime proc_exe_ino_ctime_duration_proc_start=%proc.exe_ino.ctime_duration_proc_start proc_cwd=%proc.cwd container_start_ts=%container.start_ts 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 %container.info) priority: CRITICAL tags: [custom_rule, container, process, tty, alg] ########################################################## # As the rule above does NOT log shell builtins (e.g. echo > # /etc/passwd), we audit all read and write requests in an interactive # shell inside container. # # custom list of files to ignore # used in "Log read and write container in an interactive shell" - list: ignored_file_names items: - /etc/ld.so.cache - /proc/mounts - macro: ignored_files condition: | (fd.name in (ignored_file_names)) - rule: Log read and write in container in an interactive shell desc: >- Log all read/write calls in a container if tere is an interactive shell attached. This should cover using shell builtins for IO. condition: >- (open_read or open_write) and container and proc.tty != 0 and proc.is_vpgid_leader=true and not ignored_files output: Read/Write in container (file=%fd.name fileraw=%fd.nameraw gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4] 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 %container.info) priority: CRITICAL tags: [custom_rule, container, process, tty, alg] ################################################ # Log event when a kernel module gets loaded # - list: allowed_container_images_loading_kernel_module items: [] - rule: Linux Kernel Module Injection Detected desc: > Inject Linux Kernel Modules from containers using insmod or modprobe with init_module and finit_module syscalls, given the precondition of sys_module effective capabilities. Profile the environment and consider allowed_container_images_loading_kernel_module to reduce noise and account for legitimate cases. condition: > kernel_module_load and container and thread.cap_effective icontains sys_module and not container.image.repository in (allowed_container_images_loading_kernel_module) output: Linux Kernel Module injection from container (parent_exepath=%proc.pexepath gparent=%proc.aname[2] gexepath=%proc.aexepath[2] module=%proc.args res=%evt.res 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 %container.info) priority: WARNING tags: [maturity_stable, host, container, process, mitre_persistence, TA0003, siem]