Skip to content

Commit

Permalink
Merge pull request #98 from draios/add-lists
Browse files Browse the repository at this point in the history
Add list support to rules file.
  • Loading branch information
mstemm authored Jul 11, 2016
2 parents 022614a + 502941b commit 8225dc0
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 67 deletions.
122 changes: 60 additions & 62 deletions rules/falco_rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,76 +63,76 @@
- macro: linux_so_dirs
condition: ubuntu_so_dirs or centos_so_dirs or fd.name=/etc/ld.so.cache

- macro: coreutils_binaries
condition: >
proc.name in (truncate, sha1sum, numfmt, fmt, fold, uniq, cut, who,
- list: coreutils_binaries
items: [
truncate, sha1sum, numfmt, fmt, fold, uniq, cut, who,
groups, csplit, sort, expand, printf, printenv, unlink, tee, chcon, stat,
basename, split, nice, yes, whoami, sha224sum, hostid, users, stdbuf,
basename, split, nice, "yes", whoami, sha224sum, hostid, users, stdbuf,
base64, unexpand, cksum, od, paste, nproc, pathchk, sha256sum, wc, test,
comm, arch, du, factor, sha512sum, md5sum, tr, runcon, env, dirname,
tsort, join, shuf, install, logname, pinky, nohup, expr, pr, tty, timeout,
tail, [, seq, sha384sum, nl, head, id, mkfifo, sum, dircolors, ptx, shred,
tac, link, chroot, vdir, chown, touch, ls, dd, uname, true, pwd, date,
chgrp, chmod, mktemp, cat, mknod, sync, ln, false, rm, mv, cp, echo,
readlink, sleep, stty, mkdir, df, dir, rmdir, touch)
tail, "[", seq, sha384sum, nl, head, id, mkfifo, sum, dircolors, ptx, shred,
tac, link, chroot, vdir, chown, touch, ls, dd, uname, "true", pwd, date,
chgrp, chmod, mktemp, cat, mknod, sync, ln, "false", rm, mv, cp, echo,
readlink, sleep, stty, mkdir, df, dir, rmdir, touch
]

# dpkg -L login | grep bin | xargs ls -ld | grep -v '^d' | awk '{print $9}' | xargs -L 1 basename | tr "\\n" ","
- macro: login_binaries
condition: proc.name in (login, systemd-logind, su, nologin, faillog, lastlog, newgrp, sg)
- list: login_binaries
items: [login, systemd-logind, su, nologin, faillog, lastlog, newgrp, sg]

# dpkg -L passwd | grep bin | xargs ls -ld | grep -v '^d' | awk '{print $9}' | xargs -L 1 basename | tr "\\n" ","
- macro: passwd_binaries
condition: >
proc.name in (shadowconfig, grpck, pwunconv, grpconv, pwck,
- list: passwd_binaries
items: [
shadowconfig, grpck, pwunconv, grpconv, pwck,
groupmod, vipw, pwconv, useradd, newusers, cppw, chpasswd, usermod,
groupadd, groupdel, grpunconv, chgpasswd, userdel, chage, chsh,
gpasswd, chfn, expiry, passwd, vigr, cpgr)
gpasswd, chfn, expiry, passwd, vigr, cpgr
]

# repoquery -l shadow-utils | grep bin | xargs ls -ld | grep -v '^d' | awk '{print $9}' | xargs -L 1 basename | tr "\\n" ","
- macro: shadowutils_binaries
condition: >
proc.name in (chage, gpasswd, lastlog, newgrp, sg, adduser, deluser, chpasswd,
- list: shadowutils_binaries
items: [
chage, gpasswd, lastlog, newgrp, sg, adduser, deluser, chpasswd,
groupadd, groupdel, addgroup, delgroup, groupmems, groupmod, grpck, grpconv, grpunconv,
newusers, pwck, pwconv, pwunconv, useradd, userdel, usermod, vigr, vipw, unix_chkpwd)
newusers, pwck, pwconv, pwunconv, useradd, userdel, usermod, vigr, vipw, unix_chkpwd
]

- macro: sysdigcloud_binaries
condition: proc.name in (setup-backend, dragent)
- list: sysdigcloud_binaries
items: [setup-backend, dragent]

- macro: sysdigcloud_binaries_parent
condition: proc.pname in (setup-backend, dragent)
- list: docker_binaries
items: [docker, exe]

- macro: docker_binaries
condition: proc.name in (docker, exe)
- list: http_server_binaries
items: [nginx, httpd, httpd-foregroun, lighttpd]

- macro: http_server_binaries
condition: proc.name in (nginx, httpd, httpd-foregroun, lighttpd)
- list: db_server_binaries
items: [mysqld]

- macro: db_server_binaries
condition: proc.name in (mysqld)

- macro: db_server_binaries_parent
condition: proc.pname in (mysqld)

- macro: server_binaries
condition: (http_server_binaries or db_server_binaries or docker_binaries or proc.name in (sshd))
- macro: server_procs
condition: proc.name in (http_server_binaries, db_server_binaries, docker_binaries, sshd)

# The truncated dpkg-preconfigu is intentional, process names are
# truncated at the sysdig level.
- macro: package_mgmt_binaries
condition: proc.name in (dpkg, dpkg-preconfigu, rpm, rpmkey, yum)
- list: package_mgmt_binaries
items: [dpkg, dpkg-preconfigu, rpm, rpmkey, yum]

- macro: package_mgmt_procs
condition: proc.name in (package_mgmt_binaries)

# A canonical set of processes that run other programs with different
# privileges or as a different user.
- macro: userexec_binaries
condition: proc.name in (sudo, su)
- list: userexec_binaries
items: [sudo, su]

- macro: user_mgmt_binaries
condition: (login_binaries or passwd_binaries or shadowutils_binaries)
- list: user_mgmt_binaries
items: [login_binaries, passwd_binaries, shadowutils_binaries]

- macro: system_binaries
condition: (coreutils_binaries or user_mgmt_binaries)
- macro: system_procs
condition: proc.name in (coreutils_binaries, user_mgmt_binaries)

- macro: mail_binaries
- macro: mail_procs
condition: proc.name in (sendmail, sendmail-msp, postfix, procmail)

- macro: sensitive_files
Expand Down Expand Up @@ -167,10 +167,8 @@
condition: ((proc.aname=sshd and proc.name != sshd) or proc.name=systemd-logind)
- macro: syslog
condition: fd.name in (/dev/log, /run/systemd/journal/syslog)
- macro: cron
condition: proc.name in (cron, crond)
- macro: parent_cron
condition: proc.pname in (cron, crond)
- list: cron_binaries
items: [cron, crond]

# System users that should never log into a system. Consider adding your own
# service users (e.g. 'apache' or 'mysqld') here.
Expand All @@ -184,32 +182,32 @@

- 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 not package_mgmt_binaries and bin_dir
condition: evt.dir = < and open_write and not package_mgmt_procs and bin_dir
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, not in a pipe installer session
condition: evt.dir = < and open_write and not shadowutils_binaries and not sysdigcloud_binaries_parent and not package_mgmt_binaries and etc_dir and not proc.sname=fbash
condition: evt.dir = < and open_write and not proc.name in (shadowutils_binaries, sysdigcloud_binaries, package_mgmt_binaries) and etc_dir and not proc.pname in (sysdigcloud_binaries) and not proc.sname=fbash
output: "File below /etc opened for writing (user=%user.name command=%proc.cmdline file=%fd.name)"
priority: WARNING

# Within a fbash session, the severity is lowered to INFO
- rule: write_etc_installer
desc: an attempt to write to any file below /etc, in a pipe installer session
condition: evt.dir = < and open_write and not shadowutils_binaries and not sysdigcloud_binaries_parent and not package_mgmt_binaries and etc_dir and proc.sname=fbash
condition: evt.dir = < and open_write and not proc.name in (shadowutils_binaries, sysdigcloud_binaries, package_mgmt_binaries) and etc_dir and not proc.pname in (sysdigcloud_binaries) and proc.sname=fbash
output: "File below /etc opened for writing (user=%user.name command=%proc.cmdline file=%fd.name) within pipe installer session"
priority: INFO

- 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 user_mgmt_binaries and not userexec_binaries and not proc.name in (iptables, ps, lsb_release, check-new-relea, dumpe2fs, accounts-daemon, bash, sshd) and not cron and sensitive_files
condition: open_read and not proc.name in (user_mgmt_binaries, userexec_binaries, cron_binaries, iptables, ps, lsb_release, check-new-relea, dumpe2fs, accounts-daemon, bash, sshd) and sensitive_files
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. 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 and proc.name!="sshd"
condition: open_read and server_procs and not proc_is_new and sensitive_files and proc.name!="sshd"
output: "Sensitive file opened for reading by trusted program after startup (user=%user.name command=%proc.cmdline file=%fd.name)"
priority: WARNING

Expand All @@ -222,19 +220,19 @@

- rule: db_program_spawned_process
desc: a database-server related program spawned a new process other than itself. This shouldn\'t occur and is a follow on from some SQL injection attacks.
condition: db_server_binaries_parent and not db_server_binaries and spawned_process
condition: proc.pname in (db_server_binaries) and not proc.name in (db_server_binaries) and spawned_process
output: "Database-related program spawned process other than itself (user=%user.name program=%proc.cmdline parent=%proc.pname)"
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 and not package_mgmt_binaries
condition: modify and bin_dir_rename and not package_mgmt_procs
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
condition: mkdir and bin_dir_mkdir and not package_mgmt_procs
output: "Directory below known binary directory created (user=%user.name command=%proc.cmdline directory=%evt.arg.path)"
priority: WARNING

Expand Down Expand Up @@ -262,7 +260,7 @@

- rule: run_shell_untrusted
desc: an attempt to spawn a shell by a non-shell program. Exceptions are made for trusted binaries.
condition: not container and proc.name = bash and spawned_process and proc.pname exists and not parent_cron and not proc.pname in (bash, sshd, sudo, docker, su, tmux, screen, emacs, systemd, login, flock, fbash, nginx, monit, supervisord, dragent)
condition: not container and proc.name = bash and spawned_process and proc.pname exists and not proc.pname in (cron_binaries, bash, sshd, sudo, docker, su, tmux, screen, emacs, systemd, login, flock, fbash, nginx, monit, supervisord, dragent)
output: "Shell spawned by untrusted binary (user=%user.name shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)"
priority: WARNING

Expand All @@ -284,9 +282,9 @@
priority: WARNING

# sockfamily ip is to exclude certain processes (like 'groups') that communicate on unix-domain sockets
- rule: system_binaries_network_activity
- rule: system_procs_network_activity
desc: any network activity performed by system binaries that are not expected to send or receive any network traffic
condition: (inbound or outbound) and (fd.sockfamily = ip and system_binaries)
condition: (inbound or outbound) and (fd.sockfamily = ip and system_procs)
output: "Known system binary sent/received network traffic (user=%user.name command=%proc.cmdline connection=%fd.name)"
priority: WARNING

Expand All @@ -302,13 +300,13 @@
# sshd, sendmail-msp, sendmail attempt to setuid to root even when running as non-root. Excluding here to avoid meaningless FPs
- rule: non_sudo_setuid
desc: an attempt to change users by calling setuid. sudo/su are excluded. user "root" is also excluded, as setuid calls typically involve dropping privileges.
condition: evt.type=setuid and evt.dir=> and not user.name=root and not userexec_binaries and not proc.name in (sshd, sendmail-msp, sendmail)
condition: evt.type=setuid and evt.dir=> and not user.name=root and not proc.name in (userexec_binaries, sshd, sendmail-msp, sendmail)
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
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: spawned_process and not proc.name in (su, sudo) and not container and user_mgmt_binaries and not parent_cron and not proc.pname in (systemd, run-parts)
condition: spawned_process and not proc.name in (su, sudo) and not container and proc.name in (user_mgmt_binaries) and not proc.pname in (cron_binaries, systemd, run-parts)
output: "User management binary command run outside of container (user=%user.name command=%proc.cmdline parent=%proc.pname)"
priority: WARNING

Expand Down Expand Up @@ -356,7 +354,7 @@
# as a part of doing the installation
- rule: installer_bash_runs_pkgmgmt
desc: an attempt by a program in a pipe installer session to run a package management binary
condition: evt.type=execve and package_mgmt_binaries and proc.sname=fbash
condition: evt.type=execve and package_mgmt_procs and proc.sname=fbash
output: "Package management program run by process in a fbash session (command=%proc.cmdline)"
priority: INFO

Expand Down Expand Up @@ -525,6 +523,6 @@

# - 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
# condition: proc.name in (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
14 changes: 12 additions & 2 deletions userspace/falco/lua/compiler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,12 @@ function check_for_ignored_syscalls_events(ast, filter_type, source)
parser.traverse_ast(ast, "BinaryRelOp", cb)
end

function compiler.compile_macro(line)
function compiler.compile_macro(line, list_defs)

for name, items in pairs(list_defs) do
line = string.gsub(line, name, table.concat(items, ", "))
end

local ast, error_msg = parser.parse_filter(line)

if (error_msg) then
Expand All @@ -174,7 +179,12 @@ end
--[[
Parses a single filter, then expands macros using passed-in table of definitions. Returns resulting AST.
--]]
function compiler.compile_filter(source, macro_defs)
function compiler.compile_filter(source, macro_defs, list_defs)

for name, items in pairs(list_defs) do
source = string.gsub(source, name, table.concat(items, ", "))
end

local ast, error_msg = parser.parse_filter(source)

if (error_msg) then
Expand Down
25 changes: 22 additions & 3 deletions userspace/falco/lua/rule_loader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ end
-- 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={}}
local state = {macros={}, lists={}, filter_ast=nil, rules_by_name={}, n_rules=0, rules_by_idx={}}

function load_rules(filename)

Expand All @@ -131,9 +131,28 @@ function load_rules(filename)
end

if (v['macro']) then
local ast = compiler.compile_macro(v['condition'])
local ast = compiler.compile_macro(v['condition'], state.lists)
state.macros[v['macro']] = ast.filter.value

elseif (v['list']) then
-- list items are represented in yaml as a native list, so no
-- parsing necessary
local items = {}

-- List items may be references to other lists, so go through
-- the items and expand any references to the items in the list
for i, item in ipairs(v['items']) do
if (state.lists[item] == nil) then
items[#items+1] = item
else
for i, exp_item in ipairs(state.lists[item]) do
items[#items+1] = exp_item
end
end
end

state.lists[v['list']] = items

else -- rule

if (v['rule'] == nil) then
Expand All @@ -150,7 +169,7 @@ function load_rules(filename)
v['level'] = priority(v['priority'])
state.rules_by_name[v['rule']] = v

local filter_ast = compiler.compile_filter(v['condition'], state.macros)
local filter_ast = compiler.compile_filter(v['condition'], state.macros, state.lists)

if (filter_ast.type == "Rule") then
state.n_rules = state.n_rules + 1
Expand Down

0 comments on commit 8225dc0

Please sign in to comment.