mirror of
https://github.com/falcosecurity/falco.git
synced 2025-07-19 09:06:48 +00:00
Merge pull request #64 from draios/add-names-descriptions
Add names descriptions
This commit is contained in:
commit
f5c3fc3a1c
28
README.md
28
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:
|
||||
|
||||
@ -264,10 +268,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!
|
||||
|
@ -36,10 +36,10 @@
|
||||
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
|
||||
condition: syscall.type = execve and evt.dir=<
|
||||
|
||||
# File categories
|
||||
- macro: terminal_file_fd
|
||||
@ -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
|
||||
@ -160,38 +163,50 @@
|
||||
condition: user.name in (bin, daemon, games, lp, mail, nobody, sshd, sync, uucp, www-data)
|
||||
|
||||
|
||||
#######
|
||||
# Rules
|
||||
#######
|
||||
###############
|
||||
# General Rules
|
||||
###############
|
||||
|
||||
# Don't write to binary dirs
|
||||
- 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)"
|
||||
- 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
|
||||
|
||||
# Don't write to /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)"
|
||||
- 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=%user.name command=%proc.cmdline file=%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
|
||||
output: "Read sensitive file (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||
- 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=%user.name command=%proc.cmdline file=%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
|
||||
output: "Read sensitive file after startup (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||
- 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: 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=%user.name command=%proc.cmdline file=%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
|
||||
output: "Read sensitive file after startup (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||
- 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)"
|
||||
priority: WARNING
|
||||
|
||||
# Don't modify binary dirs
|
||||
- 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)"
|
||||
- rule: modify_binary_dirs
|
||||
desc: an attempt to modify any file below a set of binary directories.
|
||||
condition: modify and bin_dir_rename and not package_mgmt_binaries
|
||||
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 and not package_mgmt_binaries
|
||||
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
|
||||
@ -203,19 +218,22 @@
|
||||
# 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
|
||||
output: "System call returned EACCESS (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||
- 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=%user.name command=%proc.cmdline syscall=%evt.type args=%evt.args)"
|
||||
priority: INFO
|
||||
|
||||
# Only sysdig related software and docker can call 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)"
|
||||
- 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=%user.name command=%proc.cmdline container=%container.id)"
|
||||
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)
|
||||
output: "Unexpected shell (%user.name %proc.name %proc.pname %evt.dir %evt.type %evt.args %fd.name)"
|
||||
- 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=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
|
||||
@ -223,48 +241,67 @@
|
||||
# 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
|
||||
output: "System user ran an interactive command (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||
- 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=%user.name command=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
|
||||
# Chmod can't be run on important binaries or sensitive files
|
||||
- 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)"
|
||||
- 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=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
|
||||
|
||||
# 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)
|
||||
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
|
||||
output: "network traffic to %proc.name (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||
- 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=%user.name command=%proc.cmdline connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
# SSH errors (failed logins, disconnects, ..)
|
||||
- condition: syslog and ssh_error_message and evt.dir = <
|
||||
output: "sshd error (%proc.name %evt.arg.data)"
|
||||
- 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 (error=%evt.buffer)"
|
||||
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
|
||||
output: "unexpected setuid call by non-sudo, non-root (%user.name %proc.name %evt.dir %evt.type %evt.args)"
|
||||
- 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 uid=%evt.arg.uid)"
|
||||
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)
|
||||
output: "user-management binary command run (%user.name %proc.name %evt.dir %evt.type %evt.args)"
|
||||
- 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=%user.name command=%proc.cmdline)"
|
||||
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
|
||||
output: "file created in /dev (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||
- 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=%user.name command=%proc.cmdline file=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
# fs-bash is a restricted version of bash suitable for use in curl <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
|
||||
@ -273,12 +310,16 @@
|
||||
- macro: elasticsearch_port
|
||||
condition: elasticsearch_cluster_port or elasticsearch_api_port
|
||||
|
||||
- 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
- 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
|
||||
@ -290,12 +331,16 @@
|
||||
- macro: activemq_port
|
||||
condition: activemq_web_port or activemq_cluster_port
|
||||
|
||||
- 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
- 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
|
||||
@ -314,12 +359,16 @@
|
||||
- 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
|
||||
output: "Unexpected Cassandra inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
- 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
# Couchbase ports
|
||||
@ -371,12 +420,16 @@
|
||||
couchbase_outgoing_ssl or couchbase_internal_rest_port or
|
||||
couchbase_internal_capi_port
|
||||
|
||||
- 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
- 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
|
||||
@ -395,12 +448,16 @@
|
||||
- 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)
|
||||
output: "Unexpected Etcd inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
- 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
|
||||
@ -410,18 +467,24 @@
|
||||
- macro: fluentd_forward_port
|
||||
condition: fd.sport=24224
|
||||
|
||||
- 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
- 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
# Gearman ports
|
||||
# http://gearman.org/protocol/
|
||||
- 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
# Zookeeper
|
||||
@ -449,31 +512,41 @@
|
||||
|
||||
# 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
|
||||
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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
- 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
|
||||
# Kafka 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
# Memcached 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
- condition: user.name = memcached and outbound
|
||||
output: "Unexpected Memcached outbound connection (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
|
||||
@ -487,27 +560,21 @@
|
||||
- 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)
|
||||
output: "Unexpected MongoDB inbound port (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
# MySQL 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)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
||||
- 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 <curl> | sh installers.
|
||||
# Don't let processes who are children of fs-bash call listen()
|
||||
- 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
|
||||
output: "unexpected setsid call by a child process of fs-bash (%proc.name %evt.args)"
|
||||
- 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 (connection=%fd.name)"
|
||||
priority: WARNING
|
||||
|
@ -45,6 +45,8 @@ static void usage()
|
||||
" -p, --pidfile <pid_file> When run as a daemon, write pid to specified file\n"
|
||||
" -e <events_file> Read the events from <events_file> (in .scap format) instead of tapping into live.\n"
|
||||
" -r <rules_file> 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 <rule> Show the name and description of the rule with name <rule> 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)
|
||||
|
@ -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.
|
||||
@ -177,12 +182,60 @@ 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.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
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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";
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user