From e500e1d771e89ee005c302e2392eae40879da535 Mon Sep 17 00:00:00 2001 From: darkjokelady Date: Thu, 13 Feb 2020 15:51:25 -0800 Subject: [PATCH] [rules] Add community rule to detect ssh login activity based on osquery events (#1127) * [rules] Add community rule to alert on ssh login activity based on osquery detection * address comments --- rules/community/guardduty/guard_duty_all.py | 4 +- rules/community/osquery/__init__.py | 0 rules/community/osquery/ssh_login_activity.py | 19 ++++ rules/matchers/matchers.py | 37 +++++++- .../rules/osquery/ssh_login_activity.json | 88 +++++++++++++++++++ 5 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 rules/community/osquery/__init__.py create mode 100644 rules/community/osquery/ssh_login_activity.py create mode 100644 tests/integration/rules/osquery/ssh_login_activity.json diff --git a/rules/community/guardduty/guard_duty_all.py b/rules/community/guardduty/guard_duty_all.py index a43020efc..f30702f1f 100644 --- a/rules/community/guardduty/guard_duty_all.py +++ b/rules/community/guardduty/guard_duty_all.py @@ -1,9 +1,9 @@ """Alert on GuardDuty""" -from rules.matchers import matchers +from rules.matchers.matchers import GuardDutyMatcher from streamalert.shared.rule import rule -@rule(logs=['cloudwatch:events'], matchers=[matchers.guard_duty]) +@rule(logs=['cloudwatch:events'], matchers=[GuardDutyMatcher.guard_duty]) def guard_duty_all(*_): """ author: spiper diff --git a/rules/community/osquery/__init__.py b/rules/community/osquery/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/rules/community/osquery/ssh_login_activity.py b/rules/community/osquery/ssh_login_activity.py new file mode 100644 index 000000000..6b4c129ba --- /dev/null +++ b/rules/community/osquery/ssh_login_activity.py @@ -0,0 +1,19 @@ +"""Detect ssh login activity based on osquery last table""" +from rules.matchers.matchers import OsqueryMatcher +from streamalert.shared.rule import rule + + +@rule(logs=['osquery:differential'], + matchers=[OsqueryMatcher.added, OsqueryMatcher.user_login]) +def ssh_login_activity(_): + """ + author: chunyong-lin + description: Detect on ssh login activity to the linux host based on osquery + last table. This rule assumes we use default osquery pack + shipped with osquery package located at + /usr/share/osquery/packs/incident-response.conf on the linux + host. Update the pack name in rules/matchers/matchers.py if different. + reference: https://osquery.io/schema/4.1.2#last + """ + + return True diff --git a/rules/matchers/matchers.py b/rules/matchers/matchers.py index 31154608c..70382582c 100644 --- a/rules/matchers/matchers.py +++ b/rules/matchers/matchers.py @@ -14,7 +14,40 @@ @rule('root_logins', logs=['osquery:differential'], matchers=[matchers.prod, matchers.pci], outputs=['pagerduty:sample-integration']) """ +class GuardDutyMatcher: + """A class contains matchers for AWS GuardDuty service""" + @classmethod + def guard_duty(cls, rec): + return rec['detail-type'] == 'GuardDuty Finding' -def guard_duty(record): - return record['detail-type'] == 'GuardDuty Finding' +class OsqueryMatcher: + """A class defines contains matchers for Osquery events""" + + _EVENT_TYPE_LOGIN = 7 + _RUNLEVELS = { + '', + 'LOGIN', + 'reboot', + 'shutdown', + 'runlevel' + } + + + @classmethod + def added(cls, rec): + return rec['action'] == 'added' + + + @classmethod + def user_login(cls, rec): + """Capture user logins from the osquery last table + This matcher assumes we use default osquery pack shipped with osquery package + located at /usr/share/osquery/packs/incident-response.conf on the linux host. + Update the pack name (rec['name']) if it is different. + """ + return ( + rec['name'] == 'pack_incident-response_last' and + int(rec['columns']['type']) == cls._EVENT_TYPE_LOGIN and + (rec['columns']['username'] not in cls._RUNLEVELS) + ) diff --git a/tests/integration/rules/osquery/ssh_login_activity.json b/tests/integration/rules/osquery/ssh_login_activity.json new file mode 100644 index 000000000..36c89f9ae --- /dev/null +++ b/tests/integration/rules/osquery/ssh_login_activity.json @@ -0,0 +1,88 @@ +[ + { + "data": { + "action": "added", + "calendarTime": "Wed Feb 12 21:38:11 2020 UTC", + "columns": { + "host": "10.0.2.2", + "pid": 12345, + "time": 1581542540, + "tty": "ttys001", + "type": "7", + "username": "vagrant" + }, + "decorations": { + "envIdentifier": "fake-environment", + "roleIdentifier": "fake-role" + }, + "epoch": "0", + "hostIdentifier": "...", + "log_type": "result", + "name": "pack_incident-response_last", + "unixTime": "1581543491" + }, + "description": "This rule alerts on ssh logins to a linux host", + "log": "osquery:differential", + "service": "kinesis", + "source": "prefix_cluster1_streamalert", + "trigger_rules": [ + "ssh_login_activity" + ] + }, + { + "data": { + "action": "added", + "calendarTime": "Wed Feb 12 21:38:11 2020 UTC", + "columns": { + "host": "10.0.2.2", + "pid": 12345, + "time": 1581542540, + "tty": "ttys001", + "type": "7", + "username": "runlevel" + }, + "decorations": { + "envIdentifier": "fake-environment", + "roleIdentifier": "fake-role" + }, + "epoch": "0", + "hostIdentifier": "...", + "log_type": "result", + "name": "pack_incident-response_last", + "unixTime": "1581543491" + }, + "description": "This rule will not alert on runlevel ssh logins", + "log": "osquery:differential", + "service": "kinesis", + "source": "prefix_cluster1_streamalert", + "trigger_rules": [] + }, + { + "data": { + "action": "added", + "calendarTime": "Wed Feb 12 21:38:11 2020 UTC", + "columns": { + "host": "10.0.2.2", + "pid": 12345, + "time": 1581542540, + "tty": "ttys001", + "type": "8", + "username": "runlevel" + }, + "decorations": { + "envIdentifier": "fake-environment", + "roleIdentifier": "fake-role" + }, + "epoch": "0", + "hostIdentifier": "...", + "log_type": "result", + "name": "pack_incident-response_last", + "unixTime": "1581543491" + }, + "description": "This rule will not alert on ssh logout(type: 8)", + "log": "osquery:differential", + "service": "kinesis", + "source": "prefix_cluster1_streamalert", + "trigger_rules": [] + } +] \ No newline at end of file