Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Demo improvements #205

Merged
merged 2 commits into from
Feb 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions docker/event-generator/event_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ void exfiltration()

shadow.open("/etc/shadow");

printf("Reading /etc/shadow and sending to 10.5.2.6:8197...\n");

if(!shadow.is_open())
{
fprintf(stderr, "Could not open /etc/shadow for reading: %s", strerror(errno));
Expand Down Expand Up @@ -219,7 +221,7 @@ void write_rpm_database() {
}

void spawn_shell() {
printf("Spawning a shell using system()...\n");
printf("Spawning a shell to run \"ls > /dev/null\" using system()...\n");
int rc;

if ((rc = system("ls > /dev/null")) != 0)
Expand Down Expand Up @@ -259,6 +261,7 @@ void mkdir_binary_dirs() {

void change_thread_namespace() {
printf("Calling setns() to change namespaces...\n");
printf("NOTE: does not result in a falco notification in containers, unless container run with --privileged or --security-opt seccomp=unconfined\n");
// It doesn't matter that the arguments to setns are
// bogus. It's the attempt to call it that will trigger the
// rule.
Expand All @@ -268,6 +271,7 @@ void change_thread_namespace() {
void system_user_interactive() {
pid_t child;

printf("Forking a child that becomes user=daemon and then tries to run /bin/login...\n");
// Fork a child and do everything in the child.
if ((child = fork()) == 0)
{
Expand Down Expand Up @@ -313,6 +317,8 @@ void system_procs_network_activity() {
void non_sudo_setuid() {
pid_t child;

printf("Forking a child that becomes \"daemon\" user and then \"root\"...\n");

// Fork a child and do everything in the child.
if ((child = fork()) == 0)
{
Expand Down Expand Up @@ -367,6 +373,9 @@ map<string, action_t> defined_actions = {{"write_binary_dir", write_binary_dir},
{"user_mgmt_binaries", user_mgmt_binaries},
{"exfiltration", exfiltration}};

// Some actions don't directly result in suspicious behavior. These
// actions are excluded from the ones run with -a all.
set<string> exclude_from_all_actions = {"exec_ls", "network_activity"};

void create_symlinks(const char *program)
{
Expand Down Expand Up @@ -394,9 +403,9 @@ void run_actions(map<string, action_t> &actions, int interval, bool once)
{
for (auto action : actions)
{
sleep(interval);
printf("***Action %s\n", action.first.c_str());
action.second();
sleep(interval);
}
if(once)
{
Expand Down Expand Up @@ -428,7 +437,7 @@ int main(int argc, char **argv)
// Parse the args
//
while((op = getopt_long(argc, argv,
"ha:i:l:",
"ha:i:l:o",
long_options, &long_index)) != -1)
{
switch(op)
Expand All @@ -437,12 +446,16 @@ int main(int argc, char **argv)
usage(argv[0]);
exit(1);
case 'a':
if((it = defined_actions.find(optarg)) == defined_actions.end())
// "all" is already implied
if (strcmp(optarg, "all") != 0)
{
fprintf(stderr, "No action with name \"%s\" known, exiting.\n", optarg);
exit(1);
if((it = defined_actions.find(optarg)) == defined_actions.end())
{
fprintf(stderr, "No action with name \"%s\" known, exiting.\n", optarg);
exit(1);
}
actions.insert(*it);
}
actions.insert(*it);
break;
case 'i':
interval = atoi(optarg);
Expand Down Expand Up @@ -482,7 +495,13 @@ int main(int argc, char **argv)

if(actions.size() == 0)
{
actions = defined_actions;
for(auto &act : defined_actions)
{
if(exclude_from_all_actions.find(act.first) == exclude_from_all_actions.end())
{
actions.insert(act);
}
}
}

setvbuf(stdout, NULL, _IONBF, 0);
Expand Down
1 change: 0 additions & 1 deletion examples/nodejs-bad-rest-api/demo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,4 @@ falco:
- /boot:/host/boot:ro
- /lib/modules:/host/lib/modules:ro
- /usr:/host/usr:ro
- ${PWD}/../../rules/falco_rules.yaml:/etc/falco_rules.yaml
tty: true
3 changes: 2 additions & 1 deletion rules/falco_rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,8 @@

- macro: trusted_containers
condition: (container.image startswith sysdig/agent or
container.image startswith sysdig/falco or
(container.image startswith sysdig/falco and
not container.image startswith sysdig/falco-event-generator) or
container.image startswith sysdig/sysdig or
container.image startswith gcr.io/google_containers/hyperkube or
container.image startswith gcr.io/google_containers/kube-proxy)
Expand Down
29 changes: 29 additions & 0 deletions test/falco_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ def setUp(self):
for rule in self.disabled_rules:
self.disabled_args = self.disabled_args + "-D " + rule + " "

self.detect_counts = self.params.get('detect_counts', '*', default=False)
if self.detect_counts == False:
self.detect_counts = {}
else:
detect_counts = {}
for item in self.detect_counts:
for item2 in item:
detect_counts[item2[0]] = item2[1]
self.detect_counts = detect_counts

self.rules_warning = self.params.get('rules_warning', '*', default=False)
if self.rules_warning == False:
self.rules_warning = sets.Set()
Expand Down Expand Up @@ -161,6 +171,23 @@ def check_detections(self, res):
if not events_detected > 0:
self.fail("Detected {} events at level {} when should have detected > 0".format(events_detected, level))

def check_detections_by_rule(self, res):
# Get the number of events detected for each rule. Must match the expected counts.
match = re.search('Triggered rules by rule name:(.*)', res.stdout, re.DOTALL)
if match is None:
self.fail("Could not find a block 'Triggered rules by rule name: ...' in falco output")

triggered_rules = match.group(1)

for rule, count in self.detect_counts.iteritems():
expected_line = '{}: {}'.format(rule, count)
match = re.search(expected_line, triggered_rules)

if match is None:
self.fail("Could not find a line '{}' in triggered rule counts '{}'".format(expected_line, triggered_rules))
else:
self.log.debug("Found expected count for {}: {}".format(rule, match.group()))

def check_outputs(self):
for output in self.outputs:
# Open the provided file and match each line against the
Expand Down Expand Up @@ -222,6 +249,8 @@ def test(self):
if len(self.rules_events) > 0:
self.check_rules_events(res)
self.check_detections(res)
if len(self.detect_counts) > 0:
self.check_detections_by_rule(res)
self.check_json_output(res)
self.check_outputs()
pass
Expand Down
19 changes: 19 additions & 0 deletions test/falco_tests.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,22 @@ trace_files: !mux
trace_file: trace_files/cat_write.scap
outputs:
- /tmp/falco_outputs/program_output.txt: Warning An open was seen

detect_counts:
detect: True
detect_level: WARNING
trace_file: traces-positive/falco-event-generator.scap
detect_counts:
- "Write below binary dir": 1
- "Read sensitive file untrusted": 3
- "Run shell in container": 1
- "Write below rpm database": 1
- "Write below etc": 1
- "System procs network activity": 1
- "Mkdir binary dirs": 1
- "System user interactive": 1
- "DB program spawned process": 1
- "Non sudo setuid": 1
- "Create files below dev": 1
- "Modify binary dirs": 2
- "Change thread namespace": 2