Compare commits

..

27 Commits

Author SHA1 Message Date
Luca Marturana
31464de885 Merge branch 'dev' into agent-master 2017-02-07 11:06:22 +01:00
Mark Stemm
df08a80a12 Merge pull request #207 from draios/address-addl-falco-fps
Additional changes to reduce FPs.
2017-02-06 16:46:11 -08:00
Mark Stemm
8a1f62c610 Additional changes to reduce FPs.
- Add flanneld as a privileged container.
 - Add parentheses grouping around many of the "x running y"
   containers. I haven't found this strictly necessary with their
   current use in rules, but this ensures they will be isolated when
   used.
 - Allow denyhosts to spawn shells--it runs iptables to add/remove hosts
   from its deny list.
2017-02-06 15:57:54 -08:00
Luca Marturana
9b308d2793 Merge branch 'dev' into agent-master 2017-02-02 12:35:47 +01:00
Mark Stemm
3d5789a297 Merge pull request #200 from draios/ndis-hids-etc-rule-updates
Rule updates related to other security products
2017-02-01 17:37:09 -08:00
Mark Stemm
b9d0857362 Rule updates related to other security products
This is a rework of a PR made by @juju4 that had a bunch of additions
related to running other security/monitoring products, including aide,
bro, icinga2, nagios, ansible, etc.

This overlapped a lot with changes I had been making to reduce
noisiness, so rather than have @juju4 deal with the conflicts I took the
changes and made a separate commit with the non-conflicting additions.

A summary of the changes:
 - Add docker-compose as a docker binary.
 - Add showq/critical-stack as setuid binaries.
 - Add lxd binaries
 - Add some additional package management binaries.
 - Add support for host intrustion detection systems like aide.
 - Add support for network intrustion detections systems like bro.
 - Add support for monitoring systems like nagios, icinga2, npcd.
 - Other one-off additions to other lists of mail/etc programs.
2017-02-01 16:25:50 -08:00
Mark Stemm
1afbaba632 Merge pull request #205 from draios/demo-improvements
Demo improvements
2017-02-01 16:24:05 -08:00
Mark Stemm
e0a5034a43 Ensure falco-event-generator actions are detected.
A new trace file falco-event-generator.scap contains the result of
running the falco event generator in docker, via:

docker run --security-opt seccomp=unconfined sysdig/falco-event-generator:latest /usr/local/bin/event_generator --once

Make sure this trace file detects the exact set of events we expect for
each rule. This required adding a new verification method
check_detections_by_rule that finds the per-rule counts and compares
them to the expected counts, which are included in the test description
under the key "detect_counts".

This is the first time a trace file for a test is actually in one of the
downloaded zip files. This means it will be tested twice (one for simple
detect-or-not, once for actual counts).

Adding this test showed a problem with Run shell in container
rule--since sysdig/falco-event-generator startswith sysdig/falco, it was
being treated as a trusted container. Modify the macro
trusted_containers to not allow falco-event-generator to be trusted.
2017-02-01 15:02:44 -08:00
Mark Stemm
6356490b1c Misc demo improvements.
Small changes to improve the use of falco_event_generator with falco:

 - In event_generator, some actions like exec_ls won't trigger
   notifications on their own. So exclude them from -a all.
 - For all actions, print details on what the action will do.
 - For actions that won't result in a falco notification in containers,
   note that in the output.
 - The short version of --once wasn't working, fix the getopt.
 - Explicitly saying -a all wasn't working, fix.
 - Don't rely on an external ruleset in the nodejs docker-compose
   demo--the built in rules are sufficient now.
2017-02-01 14:51:18 -08:00
Mark Stemm
511d0997da Merge pull request #204 from draios/cmake-dependencies
CMakeLists: add dependencies to lyaml project (fix #130)
2017-01-31 14:40:05 -08:00
Riccardo Schirone
6f9f1e4792 CMakeLists: add dependencies to lyaml project 2017-01-31 21:57:26 +00:00
Luca Marturana
a99f09da96 Merge branch 'dev' into agent-master 2017-01-31 11:47:33 +01:00
Mark Stemm
c09b6390a3 Merge pull request #202 from draios/more-spurious-alerts
Address more spurious alerts
2017-01-27 12:21:22 -08:00
Mark Stemm
3f2814259a Address more spurious alerts
- Add a second possible location for denyhosts
 - Add PM2 (http://pm2.keymetrics.io/) as a shell spawner.
 - There was a bug in use of ansible_running_python. We actually need
   two variants depending on whether ansible is the parent or current
   process. parent_ansble_running_python is used for Run shell
   untrusted, ansible_running_python is used for other rules.
2017-01-27 11:49:02 -08:00
Mark Stemm
b04bccd1a7 Merge pull request #201 from draios/remove-cchh
Remove cchh image.
2017-01-27 10:14:51 -08:00
Mark Stemm
e21fecf0ef Remove cchh image.
We had added this image while the changes in
https://github.com/draios/falco/pull/177 made it to everyone. This is in
a release now, so we'll remove it from the rule set.
2017-01-27 09:03:25 -08:00
Mark Stemm
ceafeca87e Merge pull request #199 from draios/no-assert-travis-debug
Set -DNDEBUG for travis debug builds.
2017-01-26 10:55:32 -08:00
Mark Stemm
9285aa59c1 Set -DNDEBUG for travis debug builds.
Within the sysdig code there are several ASSERTS() that can occur for
error paths that aren't truly critical, such as:

17:33:52 DEBUG| [stderr] falco: /home/travis/build/draios/sysdig/userspace/libsinsp/parsers.cpp:1657: static void sinsp_parser::parse_openat_dir(sinsp_evt*, char*, int64_t, std::string*): Assertion `false' failed.

Looking at the code, it's not a truly fatal error, just an inability to
find fd information:

----
     if(evt->m_fdinfo == NULL)
     {
             ASSERT(false);
             *sdir = "<UNKNOWN>";
     }
----

When running regression tests in travis, we don't want these ASSERTs to
cause falco to exit.

To allow this, in CMakeLists.txt only set DRAIOS_DEBUG_FLAGS if it
wasn't already set, and in travis's cmake, add -DNDEBUG to
DRAIOS_DEBUG_FLAGS.
2017-01-26 10:12:11 -08:00
Luca Marturana
1e0ddba11a Merge branch 'dev' into agent-master 2017-01-25 18:08:35 +01:00
Mark Stemm
34e17cb951 Several changes to reduce FPs
Several changes to reduce spurious alerts when managing machines via
ansible:

 - Add ansible_running_python (that is, ansible-spawned python scripts)
   as scripts that can read sensitive files and write below
   /etc. Notably this is the user ansible module.
 - Also add comments to ansible_running_python suggesting users make it
   more strict by specifically naming the root directory for ansible
   scripts.
 - Add pypy as a python variant that can run ansible-related scripts.

Also other changes to reduce FPs:

 - add apt-add-reposit, apt-auto-remova (truncation intentional),
   apt-get, apt, apt-key as package management programs, and add package
   management binaries to the set of shell spawners. The overlapping
   binaries that were in known_shell_spawn_binaries were removed.
 - add passwd_binaries, gpg, insserv, apparmor_parser, update-mime,
   tzdata.{config,postinst}, systemd-machine, and debconf-show to
   the set of binaries that can write below /etc.
 - Add vsftpd as a program that can read sensitive files.
 - Add additional programs (incl. python support programs like pip,
   pycompile) as ones that can spawn shells.
 - Allow privileged containers to spawn shells.
 - Break out the set of files below /dev that are written to with O_CREAT
   into a separate list, and add /dev/random,urandom,console to the list.
 - Add python running denyhosts as a program that can write below /etc.
 - Also add binaries starting with linux-image- as ones that can spawn
   shells. These are perl scripts run as a part of installing
   linux-image-N.N packages.
2017-01-25 08:34:52 -08:00
Mark Stemm
bc83ac18a0 Allow shells spawned by ansible.
Changes to allow shells spawned by ansible. In general this is actually
pretty difficult--on the remote managed machine, ansible performs
actions simply by running python over ssh without any explicit ansible
helper or command line.

One (weak) hint is that the python scripts being run are usually under a
directory with ansible in the name. So use that as the basis for a macro
ansible_running_python. In turn, that macro is used as a negative
condition for the run shell untrusted rule.

This is a pretty fragile and easily exploited condition, so add a note
to the macro saying so.
2017-01-19 15:09:24 -08:00
Mark Stemm
10d0c8f982 Add a local dockerfile variant.
Add a local dockerfile variant that allows creating an image from a
local .deb package.
2017-01-17 10:24:38 -08:00
Mark Stemm
8f53bcbb05 Patch jq 1.5 with a fix for security vulns.
After downloading jq 1.5, apply the changes in
stedolan/jq@8eb1367
by downloading the commit as a patch and applying it. This fixes
CVE-2015-8863.
2017-01-17 10:24:38 -08:00
Mark Stemm
7286b50f4d Update libcurl to 7.52.1.
This fixes a set of ~10 security vulnerabilities.
2017-01-17 10:24:38 -08:00
Mark Stemm
4c60b7c1d2 Update openssl to 1.0.2j.
This fixes a set of ~25 security vulnerabilities.
2017-01-17 10:24:38 -08:00
Mark Stemm
85480f32d6 Avoid FPs resulting from ubuntu weekly cron jobs
Feedback from a falco user:

--
to more findings from last night:

logrotate cronjob (Debian default):

Shell spawned by untrusted binary (user=root shell=sh parent=logrotate cmdline=sh -c invoke-rc.d rsyslog rotate > /dev/null logrotate_script /var/log/syslog)

passwd cronjob (Debian default):

Sensitive file opened for reading by non-trusted program (user=root name=cmp command=cmp -s shadow.bak /etc/shadow file=/etc/shadow)
--

New macro cmp_cp_by_passwd allows cmp/cp to be run by passwd to examine
sensitive files. Add logrotate as a program that can spawn a shell.

Also do some cleanups, moving items to lists and splitting long
single-line conditions into multiple lines.
2017-01-17 09:12:53 -08:00
Luca Marturana
4139370df5 Merge branch 'agent-master' into dev
agent-master went out of sync, probably some rebase/forcepush happened
on dev. Used `git merge -s ours agent-master` here to put all the
commits of agent-master on dev and ignoring anything from agent-master.

So now we can merge from dev to agent-master with fast forward and no
conflicts
2017-01-17 10:58:08 +01:00
9 changed files with 278 additions and 32 deletions

View File

@@ -32,7 +32,7 @@ script:
- cd ..
- mkdir build
- cd build
- cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE
- cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DDRAIOS_DEBUG_FLAGS="-D_DEBUG -DNDEBUG"
- make VERBOSE=1
- make package
- cd ..

View File

@@ -14,7 +14,9 @@ if(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE Release)
endif()
set(DRAIOS_DEBUG_FLAGS "-D_DEBUG")
if(NOT DRAIOS_DEBUG_FLAGS)
set(DRAIOS_DEBUG_FLAGS "-D_DEBUG")
endif()
set(CMAKE_C_FLAGS "-Wall -ggdb ${DRAIOS_FEATURE_FLAGS}")
set(CMAKE_CXX_FLAGS "-Wall -ggdb --std=c++0x ${DRAIOS_FEATURE_FLAGS}")
@@ -51,7 +53,7 @@ option(USE_BUNDLED_DEPS "Enable bundled dependencies instead of using the system
#
# zlib
#
option(USE_BUNDLED_ZLIB "Enable building of the bundled zlib" ${USE_BUNDLED_DEPS})
if(NOT USE_BUNDLED_ZLIB)
@@ -99,6 +101,7 @@ else()
CONFIGURE_COMMAND ./configure --disable-maintainer-mode --enable-all-static --disable-dependency-tracking
BUILD_COMMAND ${CMD_MAKE} LDFLAGS=-all-static
BUILD_IN_SOURCE 1
PATCH_COMMAND wget -O jq-1.5-fix-tokenadd.patch https://github.com/stedolan/jq/commit/8eb1367ca44e772963e704a700ef72ae2e12babd.patch && patch -i jq-1.5-fix-tokenadd.patch
INSTALL_COMMAND "")
endif()
@@ -204,8 +207,8 @@ else()
message(STATUS "Using bundled openssl in '${OPENSSL_BUNDLE_DIR}'")
ExternalProject_Add(openssl
URL "http://download.draios.com/dependencies/openssl-1.0.2d.tar.gz"
URL_MD5 "38dd619b2e77cbac69b99f52a053d25a"
URL "http://download.draios.com/dependencies/openssl-1.0.2j.tar.gz"
URL_MD5 "96322138f0b69e61b7212bc53d5e912b"
CONFIGURE_COMMAND ./config shared --prefix=${OPENSSL_INSTALL_DIR}
BUILD_COMMAND ${CMD_MAKE}
BUILD_IN_SOURCE 1
@@ -235,8 +238,8 @@ else()
ExternalProject_Add(curl
DEPENDS openssl
URL "http://download.draios.com/dependencies/curl-7.45.0.tar.bz2"
URL_MD5 "62c1a352b28558f25ba6209214beadc8"
URL "http://download.draios.com/dependencies/curl-7.52.1.tar.bz2"
URL_MD5 "dd014df06ff1d12e173de86873f9f77a"
CONFIGURE_COMMAND ./configure ${CURL_SSL_OPTION} --disable-shared --enable-optimize --disable-curldebug --disable-rt --enable-http --disable-ftp --disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-sspi --disable-ntlm-wb --disable-tls-srp --without-winssl --without-darwinssl --without-polarssl --without-cyassl --without-nss --without-axtls --without-ca-path --without-ca-bundle --without-libmetalink --without-librtmp --without-winidn --without-libidn --without-nghttp2 --without-libssh2
BUILD_COMMAND ${CMD_MAKE}
BUILD_IN_SOURCE 1
@@ -318,6 +321,13 @@ if(NOT USE_BUNDLED_LIBYAML)
message(FATAL_ERROR "Couldn't find system libyaml")
endif()
else()
find_path(AUTORECONF_BIN NAMES autoreconf)
if(AUTORECONF_BIN)
message(STATUS "Found autoreconf: ${AUTORECONF_BIN}")
else()
message(FATAL_ERROR "Couldn't find system autoreconf. Please install autoreconf before continuing or use system libyaml")
endif()
set(LIBYAML_SRC "${PROJECT_BINARY_DIR}/libyaml-prefix/src/libyaml/src")
set(LIBYAML_LIB "${LIBYAML_SRC}/.libs/libyaml.a")
ExternalProject_Add(libyaml
@@ -348,6 +358,7 @@ else()
set(LYAML_SRC "${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/ext/yaml")
set(LYAML_LIB "${LYAML_SRC}/.libs/yaml.a")
ExternalProject_Add(lyaml
DEPENDS libyaml luajit
URL "http://download.draios.com/dependencies/lyaml-release-v6.0.tar.gz"
URL_MD5 "dc3494689a0dce7cf44e7a99c72b1f30"
BUILD_COMMAND ${CMD_MAKE}

View File

@@ -97,6 +97,8 @@ void exfiltration()
shadow.open("/etc/shadow");
printf("Reading /etc/shadow and sending to 10.5.2.6:8197...\n");
if(!shadow.is_open())
{
fprintf(stderr, "Could not open /etc/shadow for reading: %s", strerror(errno));
@@ -219,7 +221,7 @@ void write_rpm_database() {
}
void spawn_shell() {
printf("Spawning a shell using system()...\n");
printf("Spawning a shell to run \"ls > /dev/null\" using system()...\n");
int rc;
if ((rc = system("ls > /dev/null")) != 0)
@@ -259,6 +261,7 @@ void mkdir_binary_dirs() {
void change_thread_namespace() {
printf("Calling setns() to change namespaces...\n");
printf("NOTE: does not result in a falco notification in containers, unless container run with --privileged or --security-opt seccomp=unconfined\n");
// It doesn't matter that the arguments to setns are
// bogus. It's the attempt to call it that will trigger the
// rule.
@@ -268,6 +271,7 @@ void change_thread_namespace() {
void system_user_interactive() {
pid_t child;
printf("Forking a child that becomes user=daemon and then tries to run /bin/login...\n");
// Fork a child and do everything in the child.
if ((child = fork()) == 0)
{
@@ -313,6 +317,8 @@ void system_procs_network_activity() {
void non_sudo_setuid() {
pid_t child;
printf("Forking a child that becomes \"daemon\" user and then \"root\"...\n");
// Fork a child and do everything in the child.
if ((child = fork()) == 0)
{
@@ -367,6 +373,9 @@ map<string, action_t> defined_actions = {{"write_binary_dir", write_binary_dir},
{"user_mgmt_binaries", user_mgmt_binaries},
{"exfiltration", exfiltration}};
// Some actions don't directly result in suspicious behavior. These
// actions are excluded from the ones run with -a all.
set<string> exclude_from_all_actions = {"exec_ls", "network_activity"};
void create_symlinks(const char *program)
{
@@ -394,9 +403,9 @@ void run_actions(map<string, action_t> &actions, int interval, bool once)
{
for (auto action : actions)
{
sleep(interval);
printf("***Action %s\n", action.first.c_str());
action.second();
sleep(interval);
}
if(once)
{
@@ -428,7 +437,7 @@ int main(int argc, char **argv)
// Parse the args
//
while((op = getopt_long(argc, argv,
"ha:i:l:",
"ha:i:l:o",
long_options, &long_index)) != -1)
{
switch(op)
@@ -437,12 +446,16 @@ int main(int argc, char **argv)
usage(argv[0]);
exit(1);
case 'a':
if((it = defined_actions.find(optarg)) == defined_actions.end())
// "all" is already implied
if (strcmp(optarg, "all") != 0)
{
fprintf(stderr, "No action with name \"%s\" known, exiting.\n", optarg);
exit(1);
if((it = defined_actions.find(optarg)) == defined_actions.end())
{
fprintf(stderr, "No action with name \"%s\" known, exiting.\n", optarg);
exit(1);
}
actions.insert(*it);
}
actions.insert(*it);
break;
case 'i':
interval = atoi(optarg);
@@ -482,7 +495,13 @@ int main(int argc, char **argv)
if(actions.size() == 0)
{
actions = defined_actions;
for(auto &act : defined_actions)
{
if(exclude_from_all_actions.find(act.first) == exclude_from_all_actions.end())
{
actions.insert(act);
}
}
}
setvbuf(stdout, NULL, _IONBF, 0);

50
docker/local/Dockerfile Normal file
View File

@@ -0,0 +1,50 @@
FROM debian:unstable
MAINTAINER Sysdig <support@sysdig.com>
ENV FALCO_VERSION 0.1.1dev
LABEL RUN="docker run -i -t -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 --name NAME IMAGE"
ENV SYSDIG_HOST_ROOT /host
ENV HOME /root
RUN cp /etc/skel/.bashrc /root && cp /etc/skel/.profile /root
ADD http://download.draios.com/apt-draios-priority /etc/apt/preferences.d/
RUN echo "deb http://httpredir.debian.org/debian jessie main" > /etc/apt/sources.list.d/jessie.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
bash-completion \
curl \
jq \
gnupg2 \
ca-certificates \
gcc \
gcc-5 \
gcc-4.9 \
sysdig && rm -rf /var/lib/apt/lists/*
# Since our base Debian image ships with GCC 5.0 which breaks older kernels, revert the
# default to gcc-4.9. Also, since some customers use some very old distributions whose kernel
# makefile is hardcoded for gcc-4.6 or so (e.g. Debian Wheezy), we pretend to have gcc 4.6/4.7
# by symlinking it to 4.9
RUN rm -rf /usr/bin/gcc \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc-4.8 \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc-4.7 \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc-4.6
RUN ln -s $SYSDIG_HOST_ROOT/lib/modules /lib/modules
ADD falco-${FALCO_VERSION}-x86_64.deb /
RUN dpkg -i /falco-${FALCO_VERSION}-x86_64.deb
COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["/usr/bin/falco"]

View File

@@ -0,0 +1,17 @@
#!/bin/bash
#set -e
# Set the SYSDIG_SKIP_LOAD variable to skip loading the sysdig kernel module
if [[ -z "${SYSDIG_SKIP_LOAD}" ]]; then
echo "* Setting up /usr/src links from host"
for i in $(ls $SYSDIG_HOST_ROOT/usr/src)
do
ln -s $SYSDIG_HOST_ROOT/usr/src/$i /usr/src/$i
done
/usr/bin/sysdig-probe-loader
fi
exec "$@"

View File

@@ -20,5 +20,4 @@ falco:
- /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

View File

@@ -99,11 +99,14 @@
items: [setup-backend, dragent, sdchecks]
- list: docker_binaries
items: [docker, dockerd, exe]
items: [docker, dockerd, exe, docker-compose]
- list: k8s_binaries
items: [hyperkube, skydns, kube2sky, exechealthz]
- list: lxd_binaries
items: [lxd, lxcfs]
- list: http_server_binaries
items: [nginx, httpd, httpd-foregroun, lighttpd]
@@ -116,7 +119,11 @@
# The truncated dpkg-preconfigu is intentional, process names are
# truncated at the sysdig level.
- list: package_mgmt_binaries
items: [dpkg, dpkg-preconfigu, dnf, rpm, rpmkey, yum, frontend]
items: [
dpkg, dpkg-preconfigu, dnf, rpm, rpmkey, yum, frontend,
apt, apt-get, aptitude, add-apt-reposit, apt-auto-remova, apt-key,
preinst, update-alternat, unattended-upgr
]
- macro: package_mgmt_procs
condition: proc.name in (package_mgmt_binaries)
@@ -135,11 +142,26 @@
- list: user_mgmt_binaries
items: [login_binaries, passwd_binaries, shadowutils_binaries]
- list: dev_creation_binaries
items: [blkid]
- list: aide_wrapper_binaries
items: [aide.wrapper, update-aide.con]
- list: hids_binaries
items: [aide]
- list: nids_binaries
items: [bro, broctl]
- list: monitoring_binaries
items: [icinga2, nrpe, npcd, check_sar_perf.]
- macro: system_procs
condition: proc.name in (coreutils_binaries, user_mgmt_binaries)
- list: mail_binaries
items: [sendmail, sendmail-msp, postfix, procmail, exim4]
items: [sendmail, sendmail-msp, postfix, procmail, exim4, pickup, showq]
- macro: sensitive_files
condition: fd.name startswith /etc and (fd.name in (/etc/shadow, /etc/sudoers, /etc/pam.conf) or fd.directory in (/etc/sudoers.d, /etc/pam.d))
@@ -190,6 +212,31 @@
- macro: system_users
condition: user.name in (bin, daemon, games, lp, mail, nobody, sshd, sync, uucp, www-data)
# SPECIAL NOTE: This macro eliminates false positives that result from
# running python scripts as a part of ansible. However, the condition
# that the command line contains "ansible" is very
# permissive. Ideally, you should change this macro to explicitly
# scope the python scripts to a specific directory (namely, your
# configured remote_tmp directory).
- macro: parent_ansible_running_python
condition: (proc.pname in (python, pypy) and proc.pcmdline contains ansible)
- macro: ansible_running_python
condition: (proc.name in (python, pypy) and proc.cmdline contains ansible)
- macro: python_running_denyhosts
condition: (proc.name=python and (proc.cmdline contains /usr/sbin/denyhosts or proc.cmdline contains /usr/local/bin/denyhosts.py))
- macro: parent_python_running_denyhosts
condition: (proc.pname=python and (proc.pcmdline contains /usr/sbin/denyhosts or proc.pcmdline contains /usr/local/bin/denyhosts.py))
- macro: parent_bro_running_python
condition: (proc.pname=python and proc.cmdline contains /usr/share/broctl)
# As a part of kernel upgrades, dpkg will spawn a perl script with the
# name linux-image-N.N. This macro matches that.
- macro: parent_linux_image_upgrade_script
condition: proc.pname startswith linux-image-
###############
# General Rules
@@ -204,9 +251,15 @@
- macro: write_etc_common
condition: >
etc_dir and evt.dir = < and open_write
and not proc.name in (shadowutils_binaries, sysdigcloud_binaries, package_mgmt_binaries, ssl_mgmt_binaries, dhcp_binaries, ldconfig.real, ldconfig, confd)
and not proc.name in (passwd_binaries, shadowutils_binaries, sysdigcloud_binaries,
package_mgmt_binaries, ssl_mgmt_binaries, dhcp_binaries,
ldconfig.real, ldconfig, confd, gpg, insserv,
apparmor_parser, update-mime, tzdata.config, tzdata.postinst,
systemd-machine, debconf-show, rollerd, bind9.postinst)
and not proc.pname in (sysdigcloud_binaries)
and not fd.directory in (/etc/cassandra, /etc/ssl/certs/java)
and not ansible_running_python
and not python_running_denyhosts
- rule: Write below etc
desc: an attempt to write to any file below /etc, not in a pipe installer session
@@ -221,22 +274,33 @@
output: "File below /etc opened for writing (user=%user.name command=%proc.cmdline file=%fd.name) within pipe installer session"
priority: INFO
- macro: cmp_cp_by_passwd
condition: proc.name in (cmp, cp) and proc.pname=passwd
- 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.
condition: sensitive_files and open_read and server_procs and not proc_is_new and proc.name!="sshd"
output: "Sensitive file opened for reading by trusted program after startup (user=%user.name command=%proc.cmdline file=%fd.name)"
priority: WARNING
- list: read_sensitive_file_binaries
items: [iptables, ps, lsb_release, check-new-relea, dumpe2fs, accounts-daemon, sshd, vsftpd, systemd]
- rule: Read sensitive file untrusted
desc: an attempt to read any sensitive file (e.g. files containing user/password/authentication information). Exceptions are made for known trusted programs.
condition: sensitive_files and open_read and not proc.name in (user_mgmt_binaries, userexec_binaries, package_mgmt_binaries, cron_binaries, iptables, ps, lsb_release, check-new-relea, dumpe2fs, accounts-daemon, shell_binaries, sshd) and not proc.cmdline contains /usr/bin/mandb
condition: >
sensitive_files and open_read
and not proc.name in (user_mgmt_binaries, userexec_binaries, package_mgmt_binaries, cron_binaries, read_sensitive_file_binaries, shell_binaries, hids_binaries)
and not cmp_cp_by_passwd
and not ansible_running_python
and not proc.cmdline contains /usr/bin/mandb
output: "Sensitive file opened for reading by non-trusted program (user=%user.name name=%proc.name command=%proc.cmdline file=%fd.name)"
priority: WARNING
# Only let rpm-related programs write to the rpm database
- rule: Write below rpm database
desc: an attempt to write to the rpm database by any non-rpm related program
condition: fd.name startswith /var/lib/rpm and open_write and not proc.name in (dnf,rpm,rpmkey,yum)
condition: fd.name startswith /var/lib/rpm and open_write and not proc.name in (dnf,rpm,rpmkey,yum) and not ansible_running_python
output: "Rpm database opened for writing by a non-rpm program (command=%proc.cmdline file=%fd.name)"
priority: WARNING
@@ -276,23 +340,48 @@
- rule: Change thread namespace
desc: an attempt to change a program/thread\'s namespace (commonly done as a part of creating a container) by calling setns.
condition: evt.type = setns and not proc.name in (docker_binaries, k8s_binaries, sysdigcloud_binaries, sysdig, nsenter) and not proc.pname in (sysdigcloud_binaries)
condition: >
evt.type = setns
and not proc.name in (docker_binaries, k8s_binaries, lxd_binaries, sysdigcloud_binaries, sysdig, nsenter)
and not proc.pname in (sysdigcloud_binaries)
output: "Namespace change (setns) by unexpected program (user=%user.name command=%proc.cmdline parent=%proc.pname %container.info)"
priority: WARNING
- list: known_shell_spawn_binaries
items: [
sshd, sudo, su, tmux, screen, emacs, systemd, login, flock, fbash,
nginx, monit, supervisord, dragent, aws, initdb, docker-compose,
make, configure, awk, falco, fail2ban-server, fleetctl,
logrotate, ansible, less, adduser, pycompile, py3compile,
pyclean, py3clean, pip, pip2, ansible-playboo, man-db,
init, pluto, mkinitramfs, unattended-upgr, watch, sysdig,
landscape-sysin, nessusd, PM2, syslog-summary
]
- rule: Run shell untrusted
desc: an attempt to spawn a shell by a non-shell program. Exceptions are made for trusted binaries.
condition: spawned_process and not container and shell_procs and proc.pname exists and not proc.pname in (cron_binaries, shell_binaries, sshd, sudo, docker_binaries, k8s_binaries, su, tmux, screen, emacs, systemd, login, flock, fbash, nginx, monit, supervisord, dragent, aws, initdb, docker-compose, make, configure, awk, falco, fail2ban-server, apt-get, apt, fleetctl)
output: "Shell spawned by untrusted binary (user=%user.name shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)"
condition: >
spawned_process and not container
and shell_procs
and proc.pname exists
and not proc.pname in (cron_binaries, shell_binaries, known_shell_spawn_binaries, docker_binaries,
k8s_binaries, package_mgmt_binaries, aide_wrapper_binaries, nids_binaries,
monitoring_binaries)
and not parent_ansible_running_python
and not parent_bro_running_python
and not parent_python_running_denyhosts
and not parent_linux_image_upgrade_script
output: "Shell spawned by untrusted binary (user=%user.name shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline pcmdline=%proc.pcmdline)"
priority: WARNING
- macro: trusted_containers
condition: (container.image startswith sysdig/agent or
container.image startswith sysdig/falco or
(container.image startswith sysdig/falco and
not container.image startswith sysdig/falco-event-generator) or
container.image startswith sysdig/sysdig or
container.image startswith gcr.io/google_containers/hyperkube or
container.image startswith gcr.io/google_containers/kube-proxy or
container.image startswith cchh/sysdig)
container.image startswith quay.io/coreos/flannel or
container.image startswith gcr.io/google_containers/kube-proxy)
- rule: File Open by Privileged Container
desc: Any open by a privileged container. Exceptions are made for known trusted images.
@@ -322,7 +411,13 @@
- rule: Run shell in container
desc: a shell was spawned by a non-shell program in a container. Container entrypoints are excluded.
condition: spawned_process and container and shell_procs and proc.pname exists and not proc.pname in (shell_binaries, docker_binaries, k8s_binaries, initdb, pg_ctl, awk, apache2, falco, cron)
condition: >
spawned_process and container
and shell_procs
and proc.pname exists
and not proc.pname in (shell_binaries, docker_binaries, k8s_binaries, lxd_binaries, aide_wrapper_binaries, nids_binaries,
monitoring_binaries, initdb, pg_ctl, awk, apache2, falco, cron)
and not trusted_containers
output: "Shell spawned in a container other than entrypoint (user=%user.name %container.info shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)"
priority: WARNING
@@ -345,8 +440,8 @@
# sshd, mail programs attempt to setuid to root even when running as non-root. Excluding here to avoid meaningless FPs
- rule: Non sudo setuid
desc: an attempt to change users by calling setuid. sudo/su are excluded. user "root" is also excluded, as setuid calls typically involve dropping privileges.
condition: evt.type=setuid and evt.dir=> and not user.name=root and not proc.name in (userexec_binaries, mail_binaries, sshd, dbus-daemon-lau)
output: "Unexpected setuid call by non-sudo, non-root program (user=%user.name command=%proc.cmdline uid=%evt.arg.uid)"
condition: evt.type=setuid and evt.dir=> and not user.name=root and not proc.name in (userexec_binaries, mail_binaries, sshd, dbus-daemon-lau, ping, ping6, critical-stack-)
output: "Unexpected setuid call by non-sudo, non-root program (user=%user.name parent=%proc.pname command=%proc.cmdline uid=%evt.arg.uid)"
priority: WARNING
- rule: User mgmt binaries
@@ -355,10 +450,17 @@
output: "User management binary command run outside of container (user=%user.name command=%proc.cmdline parent=%proc.pname)"
priority: WARNING
- list: allowed_dev_files
items: [/dev/null, /dev/stdin, /dev/stdout, /dev/stderr, /dev/tty, /dev/random, /dev/urandom, /dev/console]
# (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: fd.directory = /dev and (evt.type = creat or (evt.type = open and evt.arg.flags contains O_CREAT)) and proc.name != blkid and not fd.name in (/dev/null,/dev/stdin,/dev/stdout,/dev/stderr,/dev/tty)
condition: >
fd.directory = /dev and
(evt.type = creat or (evt.type = open and evt.arg.flags contains O_CREAT))
and not proc.name in (dev_creation_binaries)
and not fd.name in (allowed_dev_files)
output: "File created below /dev by untrusted program (user=%user.name command=%proc.cmdline file=%fd.name)"
priority: WARNING

View File

@@ -56,6 +56,16 @@ class FalcoTest(Test):
for rule in self.disabled_rules:
self.disabled_args = self.disabled_args + "-D " + rule + " "
self.detect_counts = self.params.get('detect_counts', '*', default=False)
if self.detect_counts == False:
self.detect_counts = {}
else:
detect_counts = {}
for item in self.detect_counts:
for item2 in item:
detect_counts[item2[0]] = item2[1]
self.detect_counts = detect_counts
self.rules_warning = self.params.get('rules_warning', '*', default=False)
if self.rules_warning == False:
self.rules_warning = sets.Set()
@@ -161,6 +171,23 @@ class FalcoTest(Test):
if not events_detected > 0:
self.fail("Detected {} events at level {} when should have detected > 0".format(events_detected, level))
def check_detections_by_rule(self, res):
# Get the number of events detected for each rule. Must match the expected counts.
match = re.search('Triggered rules by rule name:(.*)', res.stdout, re.DOTALL)
if match is None:
self.fail("Could not find a block 'Triggered rules by rule name: ...' in falco output")
triggered_rules = match.group(1)
for rule, count in self.detect_counts.iteritems():
expected_line = '{}: {}'.format(rule, count)
match = re.search(expected_line, triggered_rules)
if match is None:
self.fail("Could not find a line '{}' in triggered rule counts '{}'".format(expected_line, triggered_rules))
else:
self.log.debug("Found expected count for {}: {}".format(rule, match.group()))
def check_outputs(self):
for output in self.outputs:
# Open the provided file and match each line against the
@@ -222,6 +249,8 @@ class FalcoTest(Test):
if len(self.rules_events) > 0:
self.check_rules_events(res)
self.check_detections(res)
if len(self.detect_counts) > 0:
self.check_detections_by_rule(res)
self.check_json_output(res)
self.check_outputs()
pass

View File

@@ -181,3 +181,22 @@ trace_files: !mux
trace_file: trace_files/cat_write.scap
outputs:
- /tmp/falco_outputs/program_output.txt: Warning An open was seen
detect_counts:
detect: True
detect_level: WARNING
trace_file: traces-positive/falco-event-generator.scap
detect_counts:
- "Write below binary dir": 1
- "Read sensitive file untrusted": 3
- "Run shell in container": 1
- "Write below rpm database": 1
- "Write below etc": 1
- "System procs network activity": 1
- "Mkdir binary dirs": 1
- "System user interactive": 1
- "DB program spawned process": 1
- "Non sudo setuid": 1
- "Create files below dev": 1
- "Modify binary dirs": 2
- "Change thread namespace": 2