From e662d1eeebafb7dd605a6a7fcfcbff63a66d77d0 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Fri, 13 May 2016 14:00:11 -0700 Subject: [PATCH 1/9] Add name/description to rules. Add name and description fields to all rules. The name field is actually a field called 'rule', which corresponds to the 'macro' field for macros. Within the rule loader, the state changes slightly. There are two indices into the set of rules 'rules_by_name' and 'rules_by_idx' (formerly 'outputs'). They both now contain the original table from the yaml parse. One field 'level' is added which is the priority mapped to a number. Get rid of the notion of default priority or output. Every rule must now provide both. Go through all current rules and add names and descriptions. --- rules/falco_rules.yaml | 180 ++++++++++++++++++---------- userspace/falco/lua/rule_loader.lua | 33 ++--- 2 files changed, 139 insertions(+), 74 deletions(-) diff --git a/rules/falco_rules.yaml b/rules/falco_rules.yaml index 4f3a230f..ae2d64d4 100644 --- a/rules/falco_rules.yaml +++ b/rules/falco_rules.yaml @@ -164,33 +164,39 @@ # Rules ####### -# Don't write to binary dirs -- condition: evt.dir = > and open_write and bin_dir +- rule: write_binary_dir + desc: an attempt to write to any file below a set of binary directories + condition: evt.dir = > and open_write and bin_dir output: "Write to bin dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -# Don't write to /etc -- condition: evt.dir = > and open_write and etc_dir +- rule: write_etc + desc: an attempt to write to any file below /etc + condition: evt.dir = > and open_write and etc_dir output: "Write to etc dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -# Don't read 'sensitive' files -- condition: open_read and not server_binaries and not userexec_binaries and not proc.name in (iptables, ps, systemd-logind, lsb_release, check-new-relea, dumpe2fs, accounts-daemon, bash) and not cron and sensitive_files +- 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: open_read and not server_binaries and not userexec_binaries and not proc.name in (iptables, ps, systemd-logind, lsb_release, check-new-relea, dumpe2fs, accounts-daemon, bash) and not cron and sensitive_files output: "Read sensitive file (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -# These processes might read sensitive files at startup, but not afterward. -- condition: open_read and server_binaries and not proc_is_new and sensitive_files +- 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. The idea is that trusted programs might read these files at startup to load initial state, but not afterwards. + condition: open_read and server_binaries and not proc_is_new and sensitive_files output: "Read sensitive file after startup (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -# Don't let databases spawn processes (i.e. workers) after startup. -- condition: db_server_binaries and not proc_is_new and spawn_process +- rule: db_program_spawn_process + desc: a database-server related program spawning a new process after startup. This shouldn\'t occur and is a followon from some SQL injection attacks. + condition: db_server_binaries and not proc_is_new and spawn_process output: "Read sensitive file after startup (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -# Don't modify binary dirs -- condition: modify and (bin_dir_rename or bin_dir_mkdir) +- rule: modify_binary_dirs + desc: an attempt to modify any file below a set of binary directories. + condition: modify and (bin_dir_rename or bin_dir_mkdir) output: "Modify bin dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING @@ -203,18 +209,21 @@ # output: "Loaded .so from unexpected dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" # priority: WARNING -# Attempts to access things that shouldn't be -- condition: evt.res = EACCES +- rule: syscall_returns_eaccess + desc: any system call that returns EACCESS. This is not always a strong indication of a problem, hence the INFO priority. + condition: evt.res = EACCESS output: "System call returned EACCESS (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: INFO -# Only sysdig related software and docker can call setns -- condition: syscall.type = setns and not proc.name in (docker, sysdig, dragent) +- 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: syscall.type = setns and not proc.name in (docker, sysdig, dragent) output: "Unexpected setns (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -# Shells can only be run by some processes. -- condition: proc.name = bash and evt.dir=< and evt.type in (clone, execve) and proc.pname exists and not parent_cron and not proc.pname in (bash, sshd, sudo, docker, su, tmux, screen, emacs, systemd, flock, fs-bash, nginx, monit, supervisord) +- rule: run_shell_untrusted + desc: an attempt to spawn a shell by a non-shell program. Exceptions are made for trusted binaries. + condition: proc.name = bash and evt.dir=< and evt.type in (clone, execve) and proc.pname exists and not parent_cron and not proc.pname in (bash, sshd, sudo, docker, su, tmux, screen, emacs, systemd, flock, fs-bash, nginx, monit, supervisord) output: "Unexpected shell (%user.name %proc.name %proc.pname %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING @@ -223,45 +232,53 @@ # output: "Interactive root (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" # priority: WARNING -# Anything run interactively by a non-login user -- condition: system_users and interactive +- rule: system_user_interactive + desc: an attempt to run interactive commands by a system (i.e. non-login) user + condition: system_users and interactive output: "System user ran an interactive command (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -# Chmod can't be run on important binaries or sensitive files -- condition: syscall.type = chmod and (system_binaries or sensitive_files) +- rule: chmod_sensitive_files + desc: an attempt to chmod any important binary or sensitive file (e.g. files containing user/password/authentication information) + condition: syscall.type = chmod and (system_binaries or sensitive_files) output: "chmod on sensitive file/system binary (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -# Shells in a container are generally not allowed, unless their parent was a shell or docker -- condition: container and proc.name = bash and evt.dir=< and evt.type in (clone, execve) and proc.pname exists and not proc.pname in (bash, docker) +- rule: run_shell_in_container + desc: an attempt to spawn a shell by a non-shell program in a container. Container entrypoints are excluded. + condition: container and proc.name = bash and evt.dir=< and evt.type in (clone, execve) and proc.pname exists and not proc.pname in (bash, docker) output: "shell in a container (%user.name %container.id %container.name %proc.name %proc.pname %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -# Network traffic to/from standard utils # sockfamily ip is to exclude certain processes (like 'groups') that communicate on unix-domain sockets -- condition: fd.sockfamily = ip and system_binaries +- rule: system_binaries_network_activity + desc: any network activity performed by system binaries that are not expected to send or receive any network traffic + condition: fd.sockfamily = ip and system_binaries output: "network traffic to %proc.name (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -# SSH errors (failed logins, disconnects, ..) -- condition: syslog and ssh_error_message and evt.dir = < +- rule: ssh_error_syslog + desc: any ssh errors (failed logins, disconnects, ...) sent to syslog + condition: syslog and ssh_error_message and evt.dir = < output: "sshd error (%proc.name %evt.arg.data)" priority: WARNING -# Non-sudo setuid. Root is allowed to setuid, as that typically involves dropping privileges. -- condition: evt.type=setuid and evt.dir=> and not user.name=root and not userexec_binaries +- rule: non_sudo_suid + 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 userexec_binaries output: "unexpected setuid call by non-sudo, non-root (%user.name %proc.name %evt.dir %evt.type %evt.args)" priority: WARNING -# User management (su and sudo are ok). Also, user management in containers is ok (some containers create custom users from a base linux distro). -- condition: not proc.name in (su, sudo) and not container and (adduser_binaries or login_binaries or passwd_binaries or shadowutils_binaries) +- rule: user_mgmt_binaries + desc: activity by any programs that can manage users, passwords, or permissions. sudo and su are excluded. Activity in containers is also excluded--some containers create custom users on top of a base linux distribution at startup. + condition: not proc.name in (su, sudo) and not container and (adduser_binaries or login_binaries or passwd_binaries or shadowutils_binaries) output: "user-management binary command run (%user.name %proc.name %evt.dir %evt.type %evt.args)" priority: WARNING -# Some rootkits hide files in /dev # (we may need to add additional checks against false positives, see: https://bugs.launchpad.net/ubuntu/+source/rkhunter/+bug/86153) -- condition: (evt.type = creat or evt.arg.flags contains O_CREAT) and proc.name != blkid and fd.directory = /dev and fd.name != /dev/null +- 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 output: "file created in /dev (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING @@ -273,11 +290,15 @@ - macro: elasticsearch_port condition: elasticsearch_cluster_port or elasticsearch_api_port -- condition: user.name = elasticsearch and inbound and not elasticsearch_port +- rule: elasticsearch_unexpected_network_inbound + desc: inbound network traffic to elasticsearch on a port other than the standard ports + condition: user.name = elasticsearch and inbound and not elasticsearch_port output: "Unexpected Elasticsearch inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -- condition: user.name = elasticsearch and outbound and not elasticsearch_cluster_port +- rule: elasticsearch_unexpected_network_outbound + desc: outbound network traffic from elasticsearch on a port other than the standard ports + condition: user.name = elasticsearch and outbound and not elasticsearch_cluster_port output: "Unexpected Elasticsearch outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING @@ -290,11 +311,15 @@ - macro: activemq_port condition: activemq_web_port or activemq_cluster_port -- condition: user.name = activemq and inbound and not activemq_port +- rule: activemq_unexpected_network_inbound + desc: inbound network traffic to activemq on a port other than the standard ports + condition: user.name = activemq and inbound and not activemq_port output: "Unexpected ActiveMQ inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -- condition: user.name = activemq and outbound and not activemq_cluster_port +- rule: activemq_unexpected_network_outbound + desc: outbound network traffic from activemq on a port other than the standard ports + condition: user.name = activemq and outbound and not activemq_cluster_port output: "Unexpected ActiveMQ outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING @@ -314,11 +339,15 @@ - macro: cassandra_port condition: cassandra_thrift_client_port or cassandra_cql_port or cassandra_cluster_port or cassandra_ssl_cluster_port or cassandra_jmx_port -- condition: user.name = cassandra and inbound and not cassandra_port +- rule: cassandra_unexpected_network_inbound + desc: inbound network traffic to cassandra on a port other than the standard ports + condition: user.name = cassandra and inbound and not cassandra_port output: "Unexpected Cassandra inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -- condition: user.name = cassandra and outbound and not (cassandra_ssl_cluster_port or cassandra_cluster_port) +- rule: cassandra_unexpected_network_outbound + desc: outbound network traffic from cassandra on a port other than the standard ports + condition: user.name = cassandra and outbound and not (cassandra_ssl_cluster_port or cassandra_cluster_port) output: "Unexpected Cassandra outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING @@ -371,11 +400,15 @@ couchbase_outgoing_ssl or couchbase_internal_rest_port or couchbase_internal_capi_port -- condition: user.name = couchbase and inbound and not couchbase_port +- rule: couchbase_unexpected_network_inbound + desc: inbound network traffic to couchbase on a port other than the standard ports + condition: user.name = couchbase and inbound and not couchbase_port output: "Unexpected Couchbase inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -- condition: user.name = couchbase and outbound and not couchbase_internal_port +- rule: couchbase_unexpected_network_outbound + desc: outbound network traffic from couchbase on a port other than the standard ports + condition: user.name = couchbase and outbound and not couchbase_internal_port output: "Unexpected Couchbase inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING @@ -395,11 +428,15 @@ - macro: etcd_peer_port condition: fd.sport=2380 # need to double-check which user etcd runs as -- condition: user.name = etcd and inbound and not (etcd_client_port or etcd_peer_port) +- rule: etcd_unexpected_network_inbound + desc: inbound network traffic to etcd on a port other than the standard ports + condition: user.name = etcd and inbound and not (etcd_client_port or etcd_peer_port) output: "Unexpected Etcd inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -- condition: user.name = etcd and outbound and not couchbase_internal_port +- rule: etcd_unexpected_network_outbound + desc: outbound network traffic from etcd on a port other than the standard ports + condition: user.name = etcd and outbound and not couchbase_internal_port output: "Unexpected Etcd outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING @@ -410,17 +447,23 @@ - macro: fluentd_forward_port condition: fd.sport=24224 -- condition: user.name = td-agent and inbound and not (fluentd_forward_port or fluentd_http_port) +- rule: fluentd_unexpected_network_inbound + desc: inbound network traffic to fluentd on a port other than the standard ports + condition: user.name = td-agent and inbound and not (fluentd_forward_port or fluentd_http_port) output: "Unexpected Fluentd inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -- condition: user.name = td-agent and outbound and not fluentd_forward_port +- rule: tdagent_unexpected_network_outbound + desc: outbound network traffic from fluentd on a port other than the standard ports + condition: user.name = td-agent and outbound and not fluentd_forward_port output: "Unexpected Fluentd outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING # Gearman ports # http://gearman.org/protocol/ -- condition: user.name = gearman and outbound and outbound and not fd.sport = 4730 +- rule: gearman_unexpected_network_outbound + desc: outbound network traffic from gearman on a port other than the standard ports + condition: user.name = gearman and outbound and outbound and not fd.sport = 4730 output: "Unexpected Gearman outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING @@ -449,7 +492,9 @@ # If you're not running HBase under the 'hbase' user, adjust first expression # in each rule below -- condition: > +- rule: hbase_unexpected_network_inbound + desc: inbound network traffic to hbase on a port other than the standard ports + condition: > user.name = hbase and inbound and not (hbase_master_port or hbase_master_info_port or hbase_regionserver_port or hbase_regionserver_info_port or hbase_rest_port or hbase_rest_info_port or @@ -457,22 +502,30 @@ output: "Unexpected HBase inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -- condition: user.name = hbase and outbound and not (zookeeper_port or hbase_master_port or hbase_regionserver_port) +- rule: hbase_unexpected_network_outbound + desc: outbound network traffic from hbase on a port other than the standard ports + condition: user.name = hbase and outbound and not (zookeeper_port or hbase_master_port or hbase_regionserver_port) output: "Unexpected HBase outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING # Kafka ports -- condition: user.name = kafka and inbound and fd.sport != 9092 +- rule: kafka_unexpected_network_inbound + desc: inbound network traffic to kafka on a port other than the standard ports + condition: user.name = kafka and inbound and fd.sport != 9092 output: "Unexpected Kafka inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING # Memcached ports -- condition: user.name = memcached and inbound and fd.sport != 11211 +- rule: memcached_unexpected_network_inbound + desc: inbound network traffic to memcached on a port other than the standard ports + condition: user.name = memcached and inbound and fd.sport != 11211 output: "Unexpected Memcached inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -- condition: user.name = memcached and outbound +- rule: memcached_network_outbound + desc: any outbound network traffic from memcached. memcached never initiates outbound connections. + condition: user.name = memcached and outbound output: "Unexpected Memcached outbound connection (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING @@ -487,27 +540,34 @@ - macro: mongodb_webserver_port condition: fd.sport = 28017 -- condition: user.name = mongodb and inbound and not (mongodb_server_port or mongodb_shardserver_port or mongodb_configserver_port or mongodb_webserver_port) +- rule: mongodb_unexpected_network_inbound + desc: inbound network traffic to mongodb on a port other than the standard ports + condition: user.name = mongodb and inbound and not (mongodb_server_port or mongodb_shardserver_port or mongodb_configserver_port or mongodb_webserver_port) output: "Unexpected MongoDB inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING # MySQL ports -- condition: user.name = mysql and inbound and fd.sport != 3306 +- rule: mysql_unexpected_network_inbound + desc: inbound network traffic to mysql on a port other than the standard ports + condition: user.name = mysql and inbound and fd.sport != 3306 output: "Unexpected MySQL inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING -- condition: http_server_binaries and inbound and fd.sport != 80 and fd.sport != 443 +- rule: http_server_unexpected_network_inbound + desc: inbound network traffic to a http server program on a port other than the standard ports + condition: http_server_binaries and inbound and fd.sport != 80 and fd.sport != 443 output: "Unexpected HTTP server inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" priority: WARNING # fs-bash is a restricted version of bash suitable for use in curl | sh installers. -# Don't let processes who are children of fs-bash call listen() -- condition: evt.type=listen and proc.aname=fs-bash +- rule: installer_bash_starts_network_server + desc: an attempt by any program that is a child of fs-bash to start listening for network connections + condition: evt.type=listen and proc.aname=fs-bash output: "unexpected listen call by a child process of fs-bash (%proc.name %evt.args)" priority: WARNING -# Don't let processes who are children of fs-bash call setsid() to escape -# their parent process either. -- condition: evt.type=setsid and proc.aname=fs-bash +- rule: installer_bash_starts_session + desc: an attempt by any program that is a child of fs-bash to start a new session (process group) + condition: evt.type=setsid and proc.aname=fs-bash output: "unexpected setsid call by a child process of fs-bash (%proc.name %evt.args)" priority: WARNING diff --git a/userspace/falco/lua/rule_loader.lua b/userspace/falco/lua/rule_loader.lua index b6c0ea7d..e7e9c7c5 100644 --- a/userspace/falco/lua/rule_loader.lua +++ b/userspace/falco/lua/rule_loader.lua @@ -5,10 +5,6 @@ --]] -local DEFAULT_OUTPUT_FORMAT = "%evt.time: %evt.num %evt.cpu %proc.name (%thread.tid) %evt.dir %evt.type %evt.args" -local DEFAULT_PRIORITY = "WARNING" - - local output = require('output') local compiler = require "compiler" local yaml = require"lyaml" @@ -116,7 +112,11 @@ local function priority(s) error("Invalid severity level: "..level) end -local state = {macros={}, filter_ast=nil, n_rules=0, outputs={}} +-- Note that the rules_by_name and rules_by_idx refer to the same rule +-- object. The by_name index is used for things like describing rules, +-- and the by_idx index is used to map the relational node index back +-- to a rule. +local state = {macros={}, filter_ast=nil, rules_by_name={}, n_rules=0, rules_by_idx={}} function load_rules(filename) @@ -135,23 +135,28 @@ function load_rules(filename) local ast = compiler.compile_macro(v['condition']) state.macros[v['macro']] = ast.filter.value - else -- filter + else -- rule - if (v['condition'] == nil) then - error ("Missing condition in rule") + if (v['rule'] == nil) then + error ("Missing name in rule") end - if (v['output'] == nil) then - error ("Missing output in rule with condition"..v['condition']) + for i, field in ipairs({'condition', 'output', 'desc', 'priority'}) do + if (v[field] == nil) then + error ("Missing "..field.." in rule with name "..v['rule']) + end end + -- Convert the priority as a string to a level now + v['level'] = priority(v['priority']) + state.rules_by_name[v['rule']] = v + local filter_ast = compiler.compile_filter(v['condition'], state.macros) if (filter_ast.type == "Rule") then state.n_rules = state.n_rules + 1 - state.outputs[state.n_rules] = {format=v['output'] or DEFAULT_OUTPUT_FORMAT, - level=priority(v['priority'] or DEFAULT_PRIORITY)} + state.rules_by_idx[state.n_rules] = v -- Store the index of this formatter in each relational expression that -- this rule contains. @@ -179,10 +184,10 @@ end function on_event(evt_, rule_id) - if state.outputs[rule_id] == nil then + if state.rules_by_idx[rule_id] == nil then error ("rule_loader.on_event(): event with invalid rule_id: ", rule_id) end - output.event(evt_, state.outputs[rule_id].level, state.outputs[rule_id].format) + output.event(evt_, state.rules_by_idx[rule_id].level, state.rules_by_idx[rule_id].output) end From 7be0454f6f0e7db822a3b14a7be419a26e370f42 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Fri, 13 May 2016 16:27:36 -0700 Subject: [PATCH 2/9] Add ability to print name/description of rules. When run with -l , falco will print the name/description of the single rule and exit. With -L, falco will print the name/description of all rules. All the work is done in lua in the rule loader. A new lua function describe_rule calls the local function describe_single_rule once or multiple times depending on -l/-L. describe_single_rule prints the rule name and a wrapped version of the rule description. --- userspace/falco/falco.cpp | 24 ++++++++++++++- userspace/falco/lua/rule_loader.lua | 48 +++++++++++++++++++++++++++++ userspace/falco/rules.cpp | 26 +++++++++++++++- userspace/falco/rules.h | 2 ++ 4 files changed, 98 insertions(+), 2 deletions(-) diff --git a/userspace/falco/falco.cpp b/userspace/falco/falco.cpp index 53d009fc..6b92058f 100644 --- a/userspace/falco/falco.cpp +++ b/userspace/falco/falco.cpp @@ -45,6 +45,8 @@ static void usage() " -p, --pidfile When run as a daemon, write pid to specified file\n" " -e Read the events from (in .scap format) instead of tapping into live.\n" " -r Rules file (defaults to value set in configuration file, or /etc/falco_rules.yaml).\n" + " -L Show the name and description of all rules and exit.\n" + " -l Show the name and description of the rule with name and exit.\n" "\n" ); } @@ -217,6 +219,8 @@ int falco_init(int argc, char **argv) lua_State* ls = NULL; bool daemon = false; string pidfilename = "/var/run/falco.pid"; + bool describe_all_rules = false; + string describe_rule = ""; static struct option long_options[] = { @@ -236,7 +240,7 @@ int falco_init(int argc, char **argv) // Parse the args // while((op = getopt_long(argc, argv, - "c:ho:e:r:dp:", + "c:ho:e:r:dp:Ll:", long_options, &long_index)) != -1) { switch(op) @@ -262,6 +266,12 @@ int falco_init(int argc, char **argv) case 'p': pidfilename = optarg; break; + case 'L': + describe_all_rules = true; + break; + case 'l': + describe_rule = optarg; + break; case '?': result = EXIT_FAILURE; goto exit; @@ -359,6 +369,18 @@ int falco_init(int argc, char **argv) inspector->set_filter(rules->get_filter()); falco_logger::log(LOG_INFO, "Parsed rules from file " + config.m_rules_filename + "\n"); + if (describe_all_rules) + { + rules->describe_rule(NULL); + goto exit; + } + + if (describe_rule != "") + { + rules->describe_rule(&describe_rule); + goto exit; + } + inspector->set_hostname_and_port_resolution_mode(false); if (config.m_json_output) diff --git a/userspace/falco/lua/rule_loader.lua b/userspace/falco/lua/rule_loader.lua index e7e9c7c5..f5cc8882 100644 --- a/userspace/falco/lua/rule_loader.lua +++ b/userspace/falco/lua/rule_loader.lua @@ -182,6 +182,54 @@ function load_rules(filename) io.flush() end +local rule_fmt = "%-50s %s" + +-- http://lua-users.org/wiki/StringRecipes, with simplifications and bugfixes +local function wrap(str, limit, indent) + indent = indent or "" + limit = limit or 72 + local here = 1 + return str:gsub("(%s+)()(%S+)()", + function(sp, st, word, fi) + if fi-here > limit then + here = st + return "\n"..indent..word + end + end) +end + +local function describe_single_rule(name) + if (state.rules_by_name[name] == nil) then + error ("No such rule: "..name) + end + + -- Wrap the description into an multiple lines each of length ~ 60 + -- chars, with indenting to line up with the first line. + local wrapped = wrap(state.rules_by_name[name]['desc'], 60, string.format(rule_fmt, "", "")) + + local line = string.format(rule_fmt, name, wrapped) + print(line) + print() +end + +-- If name is nil, describe all rules +function describe_rule(name) + + print() + local line = string.format(rule_fmt, "Rule", "Description") + print(line) + line = string.format(rule_fmt, "----", "-----------") + print(line) + + if name == nil then + for rulename, rule in pairs(state.rules_by_name) do + describe_single_rule(rulename) + end + else + describe_single_rule(name) + end +end + function on_event(evt_, rule_id) if state.rules_by_idx[rule_id] == nil then diff --git a/userspace/falco/rules.cpp b/userspace/falco/rules.cpp index 5e3fa45a..dc2b7072 100644 --- a/userspace/falco/rules.cpp +++ b/userspace/falco/rules.cpp @@ -89,10 +89,34 @@ void falco_rules::load_rules(string rules_filename) throw sinsp_exception(err); } } else { - throw sinsp_exception("No function " + m_lua_load_rules + " found in lua compiler module"); + throw sinsp_exception("No function " + m_lua_load_rules + " found in lua rule module"); } } +void falco_rules::describe_rule(std::string *rule) +{ + lua_getglobal(m_ls, m_lua_describe_rule.c_str()); + if(lua_isfunction(m_ls, -1)) + { + if (rule == NULL) + { + lua_pushnil(m_ls); + } else { + lua_pushstring(m_ls, rule->c_str()); + } + + if(lua_pcall(m_ls, 1, 0, 0) != 0) + { + const char* lerr = lua_tostring(m_ls, -1); + string err = "Could not describe " + (rule == NULL ? "all rules" : "rule " + *rule) + ": " + string(lerr); + throw sinsp_exception(err); + } + } else { + throw sinsp_exception("No function " + m_lua_describe_rule + " found in lua rule module"); + } +} + + sinsp_filter* falco_rules::get_filter() { return m_lua_parser->get_filter(); diff --git a/userspace/falco/rules.h b/userspace/falco/rules.h index 0d5655e8..91bf6fa5 100644 --- a/userspace/falco/rules.h +++ b/userspace/falco/rules.h @@ -9,6 +9,7 @@ class falco_rules falco_rules(sinsp* inspector, lua_State *ls, string lua_main_filename); ~falco_rules(); void load_rules(string rules_filename); + void describe_rule(string *rule); sinsp_filter* get_filter(); private: @@ -22,4 +23,5 @@ class falco_rules string m_lua_ignored_syscalls = "ignored_syscalls"; string m_lua_ignored_events = "ignored_events"; string m_lua_on_event = "on_event"; + string m_lua_describe_rule = "describe_rule"; }; From 4313c9f7a301bc7ebc6aa2cec89bb9e523ff0862 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Fri, 13 May 2016 17:25:45 -0700 Subject: [PATCH 3/9] Tidy up output of existing rules. Try to clean up the language of the existing rule set, expanding the output when possible, removing %evt.dir in most cases. There is one substantive change: the mkdir half of modify_binary_dirs was split out into its own rule mkdir_binary_dirs. --- rules/falco_rules.yaml | 92 ++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/rules/falco_rules.yaml b/rules/falco_rules.yaml index ae2d64d4..0589e82f 100644 --- a/rules/falco_rules.yaml +++ b/rules/falco_rules.yaml @@ -36,8 +36,8 @@ condition: syscall.type in (remove, rmdir, unlink, unlink_at) - macro: modify - condition: rename or mkdir or remove - + condition: rename or remove + - macro: spawn_process condition: syscall.type = execve @@ -167,37 +167,43 @@ - rule: write_binary_dir desc: an attempt to write to any file below a set of binary directories condition: evt.dir = > and open_write and bin_dir - output: "Write to bin dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "File below a known binary directory opened for writing (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: write_etc desc: an attempt to write to any file below /etc condition: evt.dir = > and open_write and etc_dir - output: "Write to etc dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "File below /etc opened for writing (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - 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: open_read and not server_binaries and not userexec_binaries and not proc.name in (iptables, ps, systemd-logind, lsb_release, check-new-relea, dumpe2fs, accounts-daemon, bash) and not cron and sensitive_files - output: "Read sensitive file (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Sensitive file opened for reading by non-trusted program (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - 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. The idea is that trusted programs might read these files at startup to load initial state, but not afterwards. condition: open_read and server_binaries and not proc_is_new and sensitive_files - output: "Read sensitive file after startup (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Sensitive file opened for reading by trusted program after startup (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: db_program_spawn_process desc: a database-server related program spawning a new process after startup. This shouldn\'t occur and is a followon from some SQL injection attacks. condition: db_server_binaries and not proc_is_new and spawn_process - output: "Read sensitive file after startup (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Database-related program spawned new process after startup (%user.name %proc.name %evt.type %evt.args)" priority: WARNING - rule: modify_binary_dirs desc: an attempt to modify any file below a set of binary directories. - condition: modify and (bin_dir_rename or bin_dir_mkdir) - output: "Modify bin dir (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + condition: modify and bin_dir_rename + output: "File below known binary directory renamed/removed (%user.name %proc.name %evt.type %evt.args %fd.name)" + priority: WARNING + +- rule: mkdir_binary_dirs + desc: an attempt to create a directory below a set of binary directories. + condition: mkdir and bin_dir_mkdir + output: "Directory below known binary directory created (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING # Don't load shared objects coming from unexpected places @@ -212,19 +218,19 @@ - rule: syscall_returns_eaccess desc: any system call that returns EACCESS. This is not always a strong indication of a problem, hence the INFO priority. condition: evt.res = EACCESS - output: "System call returned EACCESS (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "System call returned EACCESS (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: INFO - 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: syscall.type = setns and not proc.name in (docker, sysdig, dragent) - output: "Unexpected setns (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Namespace change (setns) by unexpected program (%user.name %proc.name %evt.type %evt.args)" priority: WARNING - rule: run_shell_untrusted desc: an attempt to spawn a shell by a non-shell program. Exceptions are made for trusted binaries. condition: proc.name = bash and evt.dir=< and evt.type in (clone, execve) and proc.pname exists and not parent_cron and not proc.pname in (bash, sshd, sudo, docker, su, tmux, screen, emacs, systemd, flock, fs-bash, nginx, monit, supervisord) - output: "Unexpected shell (%user.name %proc.name %proc.pname %evt.dir %evt.type %evt.args %fd.name)" + output: "Shell spawned by untrusted binary (%user.name %proc.name %proc.pname %evt.type %evt.args)" priority: WARNING # Anything run interactively by root @@ -235,51 +241,51 @@ - rule: system_user_interactive desc: an attempt to run interactive commands by a system (i.e. non-login) user condition: system_users and interactive - output: "System user ran an interactive command (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "System user ran an interactive command (%user.name %proc.name %evt.type %evt.args)" priority: WARNING - rule: chmod_sensitive_files desc: an attempt to chmod any important binary or sensitive file (e.g. files containing user/password/authentication information) condition: syscall.type = chmod and (system_binaries or sensitive_files) - output: "chmod on sensitive file/system binary (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Permissions change (chmod) on sensitive file/system binary (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: run_shell_in_container desc: an attempt to spawn a shell by a non-shell program in a container. Container entrypoints are excluded. condition: container and proc.name = bash and evt.dir=< and evt.type in (clone, execve) and proc.pname exists and not proc.pname in (bash, docker) - output: "shell in a container (%user.name %container.id %container.name %proc.name %proc.pname %evt.dir %evt.type %evt.args %fd.name)" + output: "Shell spawned in a container other than entrypoint (%user.name %container.id %container.name %proc.name %proc.pname %evt.type %evt.args)" priority: WARNING # sockfamily ip is to exclude certain processes (like 'groups') that communicate on unix-domain sockets - rule: system_binaries_network_activity desc: any network activity performed by system binaries that are not expected to send or receive any network traffic condition: fd.sockfamily = ip and system_binaries - output: "network traffic to %proc.name (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Known system binary sent/received network traffic (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: ssh_error_syslog desc: any ssh errors (failed logins, disconnects, ...) sent to syslog condition: syslog and ssh_error_message and evt.dir = < - output: "sshd error (%proc.name %evt.arg.data)" + output: "sshd sent error message to syslog (%proc.name %evt.arg.data)" priority: WARNING - rule: non_sudo_suid 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 userexec_binaries - output: "unexpected setuid call by non-sudo, non-root (%user.name %proc.name %evt.dir %evt.type %evt.args)" + output: "Unexpected setuid call by non-sudo, non-root program (%user.name %proc.name %evt.type %evt.args)" priority: WARNING - rule: user_mgmt_binaries desc: activity by any programs that can manage users, passwords, or permissions. sudo and su are excluded. Activity in containers is also excluded--some containers create custom users on top of a base linux distribution at startup. condition: not proc.name in (su, sudo) and not container and (adduser_binaries or login_binaries or passwd_binaries or shadowutils_binaries) - output: "user-management binary command run (%user.name %proc.name %evt.dir %evt.type %evt.args)" + output: "User management binary command run outside of container (%user.name %proc.name %evt.type %evt.args)" priority: WARNING # (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 - output: "file created in /dev (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "File created below /dev by untrusted program (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING # Elasticsearch ports @@ -293,13 +299,13 @@ - rule: elasticsearch_unexpected_network_inbound desc: inbound network traffic to elasticsearch on a port other than the standard ports condition: user.name = elasticsearch and inbound and not elasticsearch_port - output: "Unexpected Elasticsearch inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Elasticsearch on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: elasticsearch_unexpected_network_outbound desc: outbound network traffic from elasticsearch on a port other than the standard ports condition: user.name = elasticsearch and outbound and not elasticsearch_cluster_port - output: "Unexpected Elasticsearch outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from Elasticsearch on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING @@ -314,13 +320,13 @@ - rule: activemq_unexpected_network_inbound desc: inbound network traffic to activemq on a port other than the standard ports condition: user.name = activemq and inbound and not activemq_port - output: "Unexpected ActiveMQ inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to ActiveMQ on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: activemq_unexpected_network_outbound desc: outbound network traffic from activemq on a port other than the standard ports condition: user.name = activemq and outbound and not activemq_cluster_port - output: "Unexpected ActiveMQ outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from ActiveMQ on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING @@ -342,13 +348,13 @@ - rule: cassandra_unexpected_network_inbound desc: inbound network traffic to cassandra on a port other than the standard ports condition: user.name = cassandra and inbound and not cassandra_port - output: "Unexpected Cassandra inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Cassandra on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: cassandra_unexpected_network_outbound desc: outbound network traffic from cassandra on a port other than the standard ports condition: user.name = cassandra and outbound and not (cassandra_ssl_cluster_port or cassandra_cluster_port) - output: "Unexpected Cassandra outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from Cassandra on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING # Couchbase ports @@ -403,13 +409,13 @@ - rule: couchbase_unexpected_network_inbound desc: inbound network traffic to couchbase on a port other than the standard ports condition: user.name = couchbase and inbound and not couchbase_port - output: "Unexpected Couchbase inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Couchbase on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: couchbase_unexpected_network_outbound desc: outbound network traffic from couchbase on a port other than the standard ports condition: user.name = couchbase and outbound and not couchbase_internal_port - output: "Unexpected Couchbase inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from Couchbase on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING @@ -431,13 +437,13 @@ - rule: etcd_unexpected_network_inbound desc: inbound network traffic to etcd on a port other than the standard ports condition: user.name = etcd and inbound and not (etcd_client_port or etcd_peer_port) - output: "Unexpected Etcd inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Etcd on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: etcd_unexpected_network_outbound desc: outbound network traffic from etcd on a port other than the standard ports condition: user.name = etcd and outbound and not couchbase_internal_port - output: "Unexpected Etcd outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from Etcd on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING @@ -450,13 +456,13 @@ - rule: fluentd_unexpected_network_inbound desc: inbound network traffic to fluentd on a port other than the standard ports condition: user.name = td-agent and inbound and not (fluentd_forward_port or fluentd_http_port) - output: "Unexpected Fluentd inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Fluentd on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: tdagent_unexpected_network_outbound desc: outbound network traffic from fluentd on a port other than the standard ports condition: user.name = td-agent and outbound and not fluentd_forward_port - output: "Unexpected Fluentd outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from Fluentd on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING # Gearman ports @@ -464,7 +470,7 @@ - rule: gearman_unexpected_network_outbound desc: outbound network traffic from gearman on a port other than the standard ports condition: user.name = gearman and outbound and outbound and not fd.sport = 4730 - output: "Unexpected Gearman outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from Gearman on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING # Zookeeper @@ -499,13 +505,13 @@ hbase_master_info_port or hbase_regionserver_port or hbase_regionserver_info_port or hbase_rest_port or hbase_rest_info_port or hbase_regionserver_thrift_port or hbase_thrift_info_port) - output: "Unexpected HBase inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to HBase on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: hbase_unexpected_network_outbound desc: outbound network traffic from hbase on a port other than the standard ports condition: user.name = hbase and outbound and not (zookeeper_port or hbase_master_port or hbase_regionserver_port) - output: "Unexpected HBase outbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from HBase on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING @@ -513,20 +519,20 @@ - rule: kafka_unexpected_network_inbound desc: inbound network traffic to kafka on a port other than the standard ports condition: user.name = kafka and inbound and fd.sport != 9092 - output: "Unexpected Kafka inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Kafka on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING # Memcached ports - rule: memcached_unexpected_network_inbound desc: inbound network traffic to memcached on a port other than the standard ports condition: user.name = memcached and inbound and fd.sport != 11211 - output: "Unexpected Memcached inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Memcached on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: memcached_network_outbound desc: any outbound network traffic from memcached. memcached never initiates outbound connections. condition: user.name = memcached and outbound - output: "Unexpected Memcached outbound connection (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Unexpected Memcached outbound connection (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING @@ -543,31 +549,31 @@ - rule: mongodb_unexpected_network_inbound desc: inbound network traffic to mongodb on a port other than the standard ports condition: user.name = mongodb and inbound and not (mongodb_server_port or mongodb_shardserver_port or mongodb_configserver_port or mongodb_webserver_port) - output: "Unexpected MongoDB inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to MongoDB on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING # MySQL ports - rule: mysql_unexpected_network_inbound desc: inbound network traffic to mysql on a port other than the standard ports condition: user.name = mysql and inbound and fd.sport != 3306 - output: "Unexpected MySQL inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to MySQL on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: http_server_unexpected_network_inbound desc: inbound network traffic to a http server program on a port other than the standard ports condition: http_server_binaries and inbound and fd.sport != 80 and fd.sport != 443 - output: "Unexpected HTTP server inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to HTTP Server on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING # fs-bash is a restricted version of bash suitable for use in curl | sh installers. - rule: installer_bash_starts_network_server desc: an attempt by any program that is a child of fs-bash to start listening for network connections condition: evt.type=listen and proc.aname=fs-bash - output: "unexpected listen call by a child process of fs-bash (%proc.name %evt.args)" + output: "Unexpected listen call by a child process of fs-bash (%proc.name %evt.type %evt.args)" priority: WARNING - rule: installer_bash_starts_session desc: an attempt by any program that is a child of fs-bash to start a new session (process group) condition: evt.type=setsid and proc.aname=fs-bash - output: "unexpected setsid call by a child process of fs-bash (%proc.name %evt.args)" + output: "Unexpected setsid call by a child process of fs-bash (%proc.name %evt.type %evt.args)" priority: WARNING From 5eb368035acd78e7069b4a5edb8f5f266f9612b4 Mon Sep 17 00:00:00 2001 From: Loris Degioanni Date: Sat, 14 May 2016 13:00:58 -0700 Subject: [PATCH 4/9] rule file improvement pass --- rules/falco_rules.yaml | 122 ++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 62 deletions(-) diff --git a/rules/falco_rules.yaml b/rules/falco_rules.yaml index 0589e82f..4dc8d313 100644 --- a/rules/falco_rules.yaml +++ b/rules/falco_rules.yaml @@ -160,50 +160,50 @@ condition: user.name in (bin, daemon, games, lp, mail, nobody, sshd, sync, uucp, www-data) -####### -# Rules -####### +############### +# General Rules +############### - rule: write_binary_dir desc: an attempt to write to any file below a set of binary directories condition: evt.dir = > and open_write and bin_dir - output: "File below a known binary directory opened for writing (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "File below a known binary directory opened for writing (user=%user.name command=%proc.cmdline file=%fd.name)" priority: WARNING - rule: write_etc desc: an attempt to write to any file below /etc condition: evt.dir = > and open_write and etc_dir - output: "File below /etc opened for writing (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "File below /etc opened for writing (user=%user.name command=%proc.cmdline file=%fd.name)" priority: WARNING - 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: open_read and not server_binaries and not userexec_binaries and not proc.name in (iptables, ps, systemd-logind, lsb_release, check-new-relea, dumpe2fs, accounts-daemon, bash) and not cron and sensitive_files - output: "Sensitive file opened for reading by non-trusted program (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Sensitive file opened for reading by non-trusted program (user=%user.name command=%proc.cmdline file=%fd.name)" priority: WARNING - 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. The idea is that trusted programs might read these files at startup to load initial state, but not afterwards. + 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: open_read and server_binaries and not proc_is_new and sensitive_files - output: "Sensitive file opened for reading by trusted program after startup (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Sensitive file opened for reading by trusted program after startup (user=%user.name command=%proc.cmdline file=%fd.name)" priority: WARNING - rule: db_program_spawn_process - desc: a database-server related program spawning a new process after startup. This shouldn\'t occur and is a followon from some SQL injection attacks. + desc: a database-server related program spawning a new process after startup. This shouldn\'t occur and is a follow on from some SQL injection attacks. condition: db_server_binaries and not proc_is_new and spawn_process - output: "Database-related program spawned new process after startup (%user.name %proc.name %evt.type %evt.args)" + output: "Database-related program spawned new process after startup (user=%user.name command=%proc.cmdline file=%fd.name)" priority: WARNING - rule: modify_binary_dirs desc: an attempt to modify any file below a set of binary directories. condition: modify and bin_dir_rename - output: "File below known binary directory renamed/removed (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "File below known binary directory renamed/removed (user=%user.name command=%proc.cmdline operation=%evt.type file=%fd.name %evt.args)" priority: WARNING - rule: mkdir_binary_dirs desc: an attempt to create a directory below a set of binary directories. condition: mkdir and bin_dir_mkdir - output: "Directory below known binary directory created (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Directory below known binary directory created (user=%user.name command=%proc.cmdline directory=%evt.arg.path)" priority: WARNING # Don't load shared objects coming from unexpected places @@ -218,19 +218,19 @@ - rule: syscall_returns_eaccess desc: any system call that returns EACCESS. This is not always a strong indication of a problem, hence the INFO priority. condition: evt.res = EACCESS - output: "System call returned EACCESS (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "System call returned EACCESS (user=%user.name command=%proc.cmdline syscall=%evt.type args=%evt.args)" priority: INFO - 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: syscall.type = setns and not proc.name in (docker, sysdig, dragent) - output: "Namespace change (setns) by unexpected program (%user.name %proc.name %evt.type %evt.args)" + output: "Namespace change (setns) by unexpected program (user=%user.name command=%proc.cmdline container=%container.id)" priority: WARNING - rule: run_shell_untrusted desc: an attempt to spawn a shell by a non-shell program. Exceptions are made for trusted binaries. condition: proc.name = bash and evt.dir=< and evt.type in (clone, execve) and proc.pname exists and not parent_cron and not proc.pname in (bash, sshd, sudo, docker, su, tmux, screen, emacs, systemd, flock, fs-bash, nginx, monit, supervisord) - output: "Shell spawned by untrusted binary (%user.name %proc.name %proc.pname %evt.type %evt.args)" + output: "Shell spawned by untrusted binary (user=%user.name shell=%proc.name parent=%proc.pname)" priority: WARNING # Anything run interactively by root @@ -241,53 +241,64 @@ - rule: system_user_interactive desc: an attempt to run interactive commands by a system (i.e. non-login) user condition: system_users and interactive - output: "System user ran an interactive command (%user.name %proc.name %evt.type %evt.args)" - priority: WARNING - -- rule: chmod_sensitive_files - desc: an attempt to chmod any important binary or sensitive file (e.g. files containing user/password/authentication information) - condition: syscall.type = chmod and (system_binaries or sensitive_files) - output: "Permissions change (chmod) on sensitive file/system binary (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "System user ran an interactive command (user=%user.name command=%proc.cmdline)" priority: WARNING - rule: run_shell_in_container desc: an attempt to spawn a shell by a non-shell program in a container. Container entrypoints are excluded. condition: container and proc.name = bash and evt.dir=< and evt.type in (clone, execve) and proc.pname exists and not proc.pname in (bash, docker) - output: "Shell spawned in a container other than entrypoint (%user.name %container.id %container.name %proc.name %proc.pname %evt.type %evt.args)" + output: "Shell spawned in a container other than entrypoint (user=%user.name container_id=%container.id container_name%container.name shell=%proc.name parent=%proc.pname)" priority: WARNING # sockfamily ip is to exclude certain processes (like 'groups') that communicate on unix-domain sockets - rule: system_binaries_network_activity desc: any network activity performed by system binaries that are not expected to send or receive any network traffic condition: fd.sockfamily = ip and system_binaries - output: "Known system binary sent/received network traffic (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Known system binary sent/received network traffic (user=%user.name command=%proc.cmdline connection=%fd.name)" priority: WARNING - rule: ssh_error_syslog desc: any ssh errors (failed logins, disconnects, ...) sent to syslog condition: syslog and ssh_error_message and evt.dir = < - output: "sshd sent error message to syslog (%proc.name %evt.arg.data)" + output: "sshd sent error message to syslog (error=%evt.buffer)" priority: WARNING - rule: non_sudo_suid 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 userexec_binaries - output: "Unexpected setuid call by non-sudo, non-root program (%user.name %proc.name %evt.type %evt.args)" + output: "Unexpected setuid call by non-sudo, non-root program (user=%user.name command=%proc.cmdline)" priority: WARNING - rule: user_mgmt_binaries desc: activity by any programs that can manage users, passwords, or permissions. sudo and su are excluded. Activity in containers is also excluded--some containers create custom users on top of a base linux distribution at startup. condition: not proc.name in (su, sudo) and not container and (adduser_binaries or login_binaries or passwd_binaries or shadowutils_binaries) - output: "User management binary command run outside of container (%user.name %proc.name %evt.type %evt.args)" + output: "User management binary command run outside of container (user=%user.name command=%proc.cmdline)" priority: WARNING # (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 - output: "File created below /dev by untrusted program (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "File created below /dev by untrusted program (user=%user.name command=%proc.cmdline file=%fd.name)" priority: WARNING +# fs-bash is a restricted version of bash suitable for use in curl | sh installers. +- rule: installer_bash_starts_network_server + desc: an attempt by any program that is a child of fs-bash to start listening for network connections + condition: evt.type=listen and proc.aname=fs-bash + output: "Unexpected listen call by a child process of fs-bash (command=%proc.cmdline)" + priority: WARNING + +- rule: installer_bash_starts_session + desc: an attempt by any program that is a child of fs-bash to start a new session (process group) + condition: evt.type=setsid and proc.aname=fs-bash + output: "Unexpected setsid call by a child process of fs-bash (command=%proc.cmdline)" + priority: WARNING + +########################### +# Application-Related Rules +########################### + # Elasticsearch ports - macro: elasticsearch_cluster_port condition: fd.sport=9300 @@ -299,13 +310,13 @@ - rule: elasticsearch_unexpected_network_inbound desc: inbound network traffic to elasticsearch on a port other than the standard ports condition: user.name = elasticsearch and inbound and not elasticsearch_port - output: "Inbound network traffic to Elasticsearch on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Elasticsearch on unexpected port (connection=%fd.name)" priority: WARNING - rule: elasticsearch_unexpected_network_outbound desc: outbound network traffic from elasticsearch on a port other than the standard ports condition: user.name = elasticsearch and outbound and not elasticsearch_cluster_port - output: "Outbound network traffic from Elasticsearch on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from Elasticsearch on unexpected port (connection=%fd.name)" priority: WARNING @@ -320,13 +331,13 @@ - rule: activemq_unexpected_network_inbound desc: inbound network traffic to activemq on a port other than the standard ports condition: user.name = activemq and inbound and not activemq_port - output: "Inbound network traffic to ActiveMQ on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to ActiveMQ on unexpected port (connection=%fd.name)" priority: WARNING - rule: activemq_unexpected_network_outbound desc: outbound network traffic from activemq on a port other than the standard ports condition: user.name = activemq and outbound and not activemq_cluster_port - output: "Outbound network traffic from ActiveMQ on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from ActiveMQ on unexpected port (connection=%fd.name)" priority: WARNING @@ -348,13 +359,13 @@ - rule: cassandra_unexpected_network_inbound desc: inbound network traffic to cassandra on a port other than the standard ports condition: user.name = cassandra and inbound and not cassandra_port - output: "Inbound network traffic to Cassandra on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Cassandra on unexpected port (connection=%fd.name)" priority: WARNING - rule: cassandra_unexpected_network_outbound desc: outbound network traffic from cassandra on a port other than the standard ports condition: user.name = cassandra and outbound and not (cassandra_ssl_cluster_port or cassandra_cluster_port) - output: "Outbound network traffic from Cassandra on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from Cassandra on unexpected port (connection=%fd.name)" priority: WARNING # Couchbase ports @@ -409,13 +420,13 @@ - rule: couchbase_unexpected_network_inbound desc: inbound network traffic to couchbase on a port other than the standard ports condition: user.name = couchbase and inbound and not couchbase_port - output: "Inbound network traffic to Couchbase on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Couchbase on unexpected port (connection=%fd.name)" priority: WARNING - rule: couchbase_unexpected_network_outbound desc: outbound network traffic from couchbase on a port other than the standard ports condition: user.name = couchbase and outbound and not couchbase_internal_port - output: "Outbound network traffic from Couchbase on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from Couchbase on unexpected port (connection=%fd.name)" priority: WARNING @@ -437,13 +448,13 @@ - rule: etcd_unexpected_network_inbound desc: inbound network traffic to etcd on a port other than the standard ports condition: user.name = etcd and inbound and not (etcd_client_port or etcd_peer_port) - output: "Inbound network traffic to Etcd on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Etcd on unexpected port (connection=%fd.name)" priority: WARNING - rule: etcd_unexpected_network_outbound desc: outbound network traffic from etcd on a port other than the standard ports condition: user.name = etcd and outbound and not couchbase_internal_port - output: "Outbound network traffic from Etcd on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from Etcd on unexpected port (connection=%fd.name)" priority: WARNING @@ -456,13 +467,13 @@ - rule: fluentd_unexpected_network_inbound desc: inbound network traffic to fluentd on a port other than the standard ports condition: user.name = td-agent and inbound and not (fluentd_forward_port or fluentd_http_port) - output: "Inbound network traffic to Fluentd on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Fluentd on unexpected port (connection=%fd.name)" priority: WARNING - rule: tdagent_unexpected_network_outbound desc: outbound network traffic from fluentd on a port other than the standard ports condition: user.name = td-agent and outbound and not fluentd_forward_port - output: "Outbound network traffic from Fluentd on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from Fluentd on unexpected port (connection=%fd.name)" priority: WARNING # Gearman ports @@ -470,7 +481,7 @@ - rule: gearman_unexpected_network_outbound desc: outbound network traffic from gearman on a port other than the standard ports condition: user.name = gearman and outbound and outbound and not fd.sport = 4730 - output: "Outbound network traffic from Gearman on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from Gearman on unexpected port (connection=%fd.name)" priority: WARNING # Zookeeper @@ -505,13 +516,13 @@ hbase_master_info_port or hbase_regionserver_port or hbase_regionserver_info_port or hbase_rest_port or hbase_rest_info_port or hbase_regionserver_thrift_port or hbase_thrift_info_port) - output: "Inbound network traffic to HBase on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to HBase on unexpected port (connection=%fd.name)" priority: WARNING - rule: hbase_unexpected_network_outbound desc: outbound network traffic from hbase on a port other than the standard ports condition: user.name = hbase and outbound and not (zookeeper_port or hbase_master_port or hbase_regionserver_port) - output: "Outbound network traffic from HBase on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Outbound network traffic from HBase on unexpected port (connection=%fd.name)" priority: WARNING @@ -519,20 +530,20 @@ - rule: kafka_unexpected_network_inbound desc: inbound network traffic to kafka on a port other than the standard ports condition: user.name = kafka and inbound and fd.sport != 9092 - output: "Inbound network traffic to Kafka on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Kafka on unexpected port (connection=%fd.name)" priority: WARNING # Memcached ports - rule: memcached_unexpected_network_inbound desc: inbound network traffic to memcached on a port other than the standard ports condition: user.name = memcached and inbound and fd.sport != 11211 - output: "Inbound network traffic to Memcached on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to Memcached on unexpected port (connection=%fd.name)" priority: WARNING - rule: memcached_network_outbound desc: any outbound network traffic from memcached. memcached never initiates outbound connections. condition: user.name = memcached and outbound - output: "Unexpected Memcached outbound connection (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Unexpected Memcached outbound connection (connection=%fd.name)" priority: WARNING @@ -549,31 +560,18 @@ - rule: mongodb_unexpected_network_inbound desc: inbound network traffic to mongodb on a port other than the standard ports condition: user.name = mongodb and inbound and not (mongodb_server_port or mongodb_shardserver_port or mongodb_configserver_port or mongodb_webserver_port) - output: "Inbound network traffic to MongoDB on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to MongoDB on unexpected port (connection=%fd.name)" priority: WARNING # MySQL ports - rule: mysql_unexpected_network_inbound desc: inbound network traffic to mysql on a port other than the standard ports condition: user.name = mysql and inbound and fd.sport != 3306 - output: "Inbound network traffic to MySQL on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" + output: "Inbound network traffic to MySQL on unexpected port (connection=%fd.name)" priority: WARNING - rule: http_server_unexpected_network_inbound desc: inbound network traffic to a http server program on a port other than the standard ports condition: http_server_binaries and inbound and fd.sport != 80 and fd.sport != 443 - output: "Inbound network traffic to HTTP Server on unexpected port (%user.name %proc.name %evt.type %evt.args %fd.name)" - priority: WARNING - -# fs-bash is a restricted version of bash suitable for use in curl | sh installers. -- rule: installer_bash_starts_network_server - desc: an attempt by any program that is a child of fs-bash to start listening for network connections - condition: evt.type=listen and proc.aname=fs-bash - output: "Unexpected listen call by a child process of fs-bash (%proc.name %evt.type %evt.args)" - priority: WARNING - -- rule: installer_bash_starts_session - desc: an attempt by any program that is a child of fs-bash to start a new session (process group) - condition: evt.type=setsid and proc.aname=fs-bash - output: "Unexpected setsid call by a child process of fs-bash (%proc.name %evt.type %evt.args)" + output: "Inbound network traffic to HTTP Server on unexpected port (connection=%fd.name)" priority: WARNING From 0a9a85d1da0f190fe023cae606539014f538f7c7 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Sat, 14 May 2016 21:51:55 -0700 Subject: [PATCH 5/9] Also update README example to reflect new format. Include full macros and rule for write_binary_dir. --- README.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index de389426..57d0b943 100644 --- a/README.md +++ b/README.md @@ -264,10 +264,24 @@ Or instead you can try using some of the simpler rules files in `rules`. Or to g Create a file with some [Falco rules](Rule-syntax-and-design). For example: ``` -write: (syscall.type=write and fd.typechar=f) or syscall.type=mkdir or syscall.type=creat or syscall.type=rename -interactive: proc.pname = bash or proc.pname = sshd -write and interactive and fd.name contains sysdig -write and interactive and fd.name contains .txt +- macro: open_write + condition: > + (evt.type=open or evt.type=openat) and + fd.typechar='f' and + (evt.arg.flags contains O_WRONLY or + evt.arg.flags contains O_RDWR or + evt.arg.flags contains O_CREAT or + evt.arg.flags contains O_TRUNC) + +- macro: bin_dir + condition: fd.directory in (/bin, /sbin, /usr/bin, /usr/sbin) + +- rule: write_binary_dir + desc: an attempt to write to any file below a set of binary directories + condition: evt.dir = > and open_write and bin_dir + output: "File below a known binary directory opened for writing (user=%user.name command=%proc.cmdline file=%fd.name)" + priority: WARNING + ``` And you will see an output event for any interactive process that touches a file with "sysdig" or ".txt" in its name! From 7436bc095231dce765509e292c3b1a047622db1a Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Sat, 14 May 2016 21:57:57 -0700 Subject: [PATCH 6/9] Allow package mgmt binaries to work in bin dirs. A new macro package_mgmt_binaries includes dpkg and rpm. Those programs are allowed to create directories and modify files below binary directories. I'm not adding them to other trusted sets for now, though. --- rules/falco_rules.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rules/falco_rules.yaml b/rules/falco_rules.yaml index 0589e82f..d0e69762 100644 --- a/rules/falco_rules.yaml +++ b/rules/falco_rules.yaml @@ -106,6 +106,9 @@ - macro: server_binaries condition: http_server_binaries or db_server_binaries or docker_binaries or proc.name in (sshd) +- macro: package_mgmt_binaries + condition: proc.name in (dpkg, rpm) + # A canonical set of processes that run other programs with different # privileges or as a different user. - macro: userexec_binaries @@ -196,13 +199,13 @@ - rule: modify_binary_dirs desc: an attempt to modify any file below a set of binary directories. - condition: modify and bin_dir_rename + condition: modify and bin_dir_rename and not package_mgmt_binaries output: "File below known binary directory renamed/removed (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING - rule: mkdir_binary_dirs desc: an attempt to create a directory below a set of binary directories. - condition: mkdir and bin_dir_mkdir + condition: mkdir and bin_dir_mkdir and not package_mgmt_binaries output: "Directory below known binary directory created (%user.name %proc.name %evt.type %evt.args %fd.name)" priority: WARNING From 4bd11ddcfc3173acefd231ab2d421f500ca9f03d Mon Sep 17 00:00:00 2001 From: Loris Degioanni Date: Sun, 15 May 2016 10:00:13 -0700 Subject: [PATCH 7/9] a couple of fixes in the rules file --- rules/falco_rules.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rules/falco_rules.yaml b/rules/falco_rules.yaml index 4dc8d313..5e5c969e 100644 --- a/rules/falco_rules.yaml +++ b/rules/falco_rules.yaml @@ -191,7 +191,7 @@ - rule: db_program_spawn_process desc: a database-server related program spawning a new process after startup. This shouldn\'t occur and is a follow on from some SQL injection attacks. condition: db_server_binaries and not proc_is_new and spawn_process - output: "Database-related program spawned new process after startup (user=%user.name command=%proc.cmdline file=%fd.name)" + output: "Database-related program spawned new process after startup (user=%user.name command=%proc.cmdline)" priority: WARNING - rule: modify_binary_dirs @@ -247,7 +247,7 @@ - rule: run_shell_in_container desc: an attempt to spawn a shell by a non-shell program in a container. Container entrypoints are excluded. condition: container and proc.name = bash and evt.dir=< and evt.type in (clone, execve) and proc.pname exists and not proc.pname in (bash, docker) - output: "Shell spawned in a container other than entrypoint (user=%user.name container_id=%container.id container_name%container.name shell=%proc.name parent=%proc.pname)" + output: "Shell spawned in a container other than entrypoint (user=%user.name container_id=%container.id container_name=%container.name shell=%proc.name parent=%proc.pname)" priority: WARNING # sockfamily ip is to exclude certain processes (like 'groups') that communicate on unix-domain sockets From fd3fa570a22a64c738451bed5abeb82795a6c520 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Sun, 15 May 2016 22:06:19 -0700 Subject: [PATCH 8/9] Add desc/rule fields to general rule documentation We'll probably want a more formal set of documentation soon, but at least they're mentioned now. Also remove socket from the list of discarded events, thinking ahead to when https://github.com/draios/sysdig/pull/591 will be merged. --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 57d0b943..5e6199dc 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,11 @@ _Tip: If you're new to sysdig and unsure what fields are available, run `sysdig #### Rules -Along with a condition, each rule includes an _output_ and a _priority_. The output format specifies the message that should be output if a matching event occurs, and follows the Sysdig [output format syntax](http://www.sysdig.org/wiki/sysdig-user-guide/#output-formatting). The priority is a case-insensitive representation of severity and should be one of "emergency", "alert", "critical", "error", "warning", "notice", "informational", or "debug". +Along with a condition, each rule includes the following fields: + +* _rule_: a short unique name for the rule +* _desc_: a longer description of what the rule detects +* _output_ and _priority_: The output format specifies the message that should be output if a matching event occurs, and follows the Sysdig [output format syntax](http://www.sysdig.org/wiki/sysdig-user-guide/#output-formatting). The priority is a case-insensitive representation of severity and should be one of "emergency", "alert", "critical", "error", "warning", "notice", "informational", or "debug". A complete rule using the above condition might be: @@ -93,7 +97,7 @@ For many more examples of rules and macros, please take a look at the accompanyi #### Ignored system calls For performance reasons, some system calls are currently discarded before Falco processing. The current list is: -`clock_getres,clock_gettime,clock_nanosleep,clock_settime,close,epoll_create,epoll_create1,epoll_ctl,epoll_pwait,epoll_wait,eventfd,fcntl,fcntl64,fstat,fstat64,getitimer,gettimeofday,nanosleep,poll,ppoll,pread64,preadv,pselect6,pwrite64,pwritev,read,readv,recv,recvfrom,recvmmsg,recvmsg,select,send,sendfile,sendfile64,sendmmsg,sendmsg,sendto,setitimer,settimeofday,shutdown,socket,splice,switch,tee,timer_create,timer_delete,timerfd_create,timerfd_gettime,timerfd_settime,timer_getoverrun,timer_gettime,timer_settime,wait4,write,writev` +`clock_getres,clock_gettime,clock_nanosleep,clock_settime,close,epoll_create,epoll_create1,epoll_ctl,epoll_pwait,epoll_wait,eventfd,fcntl,fcntl64,fstat,fstat64,getitimer,gettimeofday,nanosleep,poll,ppoll,pread64,preadv,pselect6,pwrite64,pwritev,read,readv,recv,recvfrom,recvmmsg,recvmsg,select,send,sendfile,sendfile64,sendmmsg,sendmsg,sendto,setitimer,settimeofday,shutdown,splice,switch,tee,timer_create,timer_delete,timerfd_create,timerfd_gettime,timerfd_settime,timer_getoverrun,timer_gettime,timer_settime,wait4,write,writev` ## Configuration From 3283ca1e5dd83911d107c86368cb7c073b314d2a Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Mon, 16 May 2016 11:39:39 -0700 Subject: [PATCH 9/9] Add some detail back to outputs. For rules where evt.args had useful information but too much information, add back specific values that have just the useful argument from the event: - spawned shells contain the commandline--it's the exit half of the exec event so the current commandline is what was exec()d to. - setuid contains the uid being switched to. While I was testing these, I had a couple of other fixes: - In the spawn shells rule, only track execve events so you don't catch clone() events that precede an exec. - in spawn_process only consider the exit half of the exec event. --- rules/falco_rules.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/rules/falco_rules.yaml b/rules/falco_rules.yaml index a344c3e2..94000e01 100644 --- a/rules/falco_rules.yaml +++ b/rules/falco_rules.yaml @@ -39,7 +39,7 @@ condition: rename or remove - macro: spawn_process - condition: syscall.type = execve + condition: syscall.type = execve and evt.dir=< # File categories - macro: terminal_file_fd @@ -232,8 +232,8 @@ - rule: run_shell_untrusted desc: an attempt to spawn a shell by a non-shell program. Exceptions are made for trusted binaries. - condition: proc.name = bash and evt.dir=< and evt.type in (clone, execve) and proc.pname exists and not parent_cron and not proc.pname in (bash, sshd, sudo, docker, su, tmux, screen, emacs, systemd, flock, fs-bash, nginx, monit, supervisord) - output: "Shell spawned by untrusted binary (user=%user.name shell=%proc.name parent=%proc.pname)" + condition: proc.name = bash and evt.dir=< and evt.type=execve and proc.pname exists and not parent_cron and not proc.pname in (bash, sshd, sudo, docker, su, tmux, screen, emacs, systemd, flock, fs-bash, nginx, monit, supervisord) + output: "Shell spawned by untrusted binary (user=%user.name shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)" priority: WARNING # Anything run interactively by root @@ -249,8 +249,8 @@ - rule: run_shell_in_container desc: an attempt to spawn a shell by a non-shell program in a container. Container entrypoints are excluded. - condition: container and proc.name = bash and evt.dir=< and evt.type in (clone, execve) and proc.pname exists and not proc.pname in (bash, docker) - output: "Shell spawned in a container other than entrypoint (user=%user.name container_id=%container.id container_name=%container.name shell=%proc.name parent=%proc.pname)" + condition: container and proc.name = bash and evt.dir=< and evt.type=execve and proc.pname exists and not proc.pname in (bash, docker) + output: "Shell spawned in a container other than entrypoint (user=%user.name container_id=%container.id container_name=%container.name shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)" priority: WARNING # sockfamily ip is to exclude certain processes (like 'groups') that communicate on unix-domain sockets @@ -266,10 +266,10 @@ output: "sshd sent error message to syslog (error=%evt.buffer)" priority: WARNING -- rule: non_sudo_suid +- 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 userexec_binaries - output: "Unexpected setuid call by non-sudo, non-root program (user=%user.name command=%proc.cmdline)" + output: "Unexpected setuid call by non-sudo, non-root program (user=%user.name command=%proc.cmdline uid=%evt.arg.uid)" priority: WARNING - rule: user_mgmt_binaries