Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #482 from ameihm0912/sshkey-alert
Browse files Browse the repository at this point in the history
add sshkey alert
  • Loading branch information
pwnbus committed Sep 27, 2017
2 parents d9bbb22 + be05df5 commit 3f8a733
Show file tree
Hide file tree
Showing 3 changed files with 220 additions and 0 deletions.
2 changes: 2 additions & 0 deletions alerts/sshkey.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# host_regex path
.*\.ignorehosts\.com /home/user/.ssh/id_rsa
101 changes: 101 additions & 0 deletions alerts/sshkey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/usr/bin/env python

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# Copyright (c) 2017 Mozilla Corporation
#
# Contributors:
# Aaron Meihm <ameihm@mozilla.com>

from lib.alerttask import AlertTask
from query_models import SearchQuery, TermMatch
import re

# This alert consumes data produced by the MIG sshkey module and mig-runner.
# sshkey related events are compared against a whitelist which is the
# alerts configuration file (sshkey.conf). The format of this whitelist
# is as follows:
#
# <host regex> <path>
#
# If a host matches the regex, and the detected key matches the path, the
# alert will not generate an alert event. If the detected key is not in
# the whitelist, an alert will be created.

class SSHKey(AlertTask):
def __init__(self):
# _whitelist contains all whitelisted key paths, loaded from the
# configuration file for the alert plugin
self._whitelist = []

AlertTask.__init__(self)
self._parse_whitelist('sshkey.conf')

def main(self):
search_query = SearchQuery(minutes=30)

search_query.add_must([
TermMatch('_type', 'event'),
TermMatch('tags', 'mig-runner-sshkey'),
])

self.filtersManual(search_query)

self.searchEventsSimple()
self.walkEvents()

# Load whitelist from file system and store in object, path specifies the
# path to load the whitelist from
def _parse_whitelist(self, path):
with open(path) as fd:
lns = [x.strip() for x in fd.readlines()]
for entry in lns:
try:
pindex = entry.index(' ')
except ValueError:
continue
self._whitelist.append({
'hostre': entry[:pindex],
'path': entry[pindex + 1:]
})

# Return false if the key path is present in the whitelist, otherwise return
# true
def _whitelist_check(self, hostname, privkey):
for went in self._whitelist:
try:
rem = re.compile(went['hostre'])
except:
continue
if rem.match(hostname) == None:
continue
if privkey['path'] == went['path']:
return False
return True

def onEvent(self, event):
# Each event could potentially contain a number of identified private keys, since
# mig-runner will send an event per host. Compare the private keys in the event
# to the keys in the whitelist, if any are missing from the whitelist we will include
# the paths in an alert and return the alert, otherwise no alert is returned.
ev = event['_source']

if 'details' not in ev:
return None
if 'private' not in ev['details'] or 'agent' not in ev['details']:
return None
hostname = ev['details']['agent']
alertkeys = [x for x in ev['details']['private'] if self._whitelist_check(hostname, x)]
if len(alertkeys) == 0:
return None

category = 'sshkey'
tags = ['sshkey']
severity = 'WARNING'
summary = 'Private keys detected on {} missing from whitelist'.format(hostname)
ret = self.createAlertDict(summary, category, tags, [event], severity)
ret['details'] = {
'private': alertkeys
}
return ret
117 changes: 117 additions & 0 deletions tests/alerts/test_sshkey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
from positive_alert_test_case import PositiveAlertTestCase
from negative_alert_test_case import NegativeAlertTestCase

from alert_test_suite import AlertTestSuite


class TestSSHKey(AlertTestSuite):
alert_filename = 'sshkey'
alert_classname = 'SSHKey'

# This event is the default positive event that will cause the
# alert to trigger
default_event = {
'_type': 'event',
'_source': {
'category': 'event',
'processid': '19690',
'severity': 'INFO',
'tags': [
'mig-runner-sshkey'
],
'hostname': 'mig-runner-host.mozilla.com',
'mozdefhostname': 'mozdef-host.mozilla.com',
'summary': 'MIG sshkey module result for key-host.mozilla.com',
'processname': '/home/migrunner/runner/plugins/sshkeyplugin.py',
'details': {
'authorizedkeys': [
{
'fingerprint_sha256': 'SHA256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
'encrypted': False,
'fingerprint_md5': '00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00',
'path': '/home/user/.ssh/authorized_keys'
}
],
'private': [
{
'fingerprint_sha256': 'SHA256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
'encrypted': False,
'fingerprint_md5': '00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00',
'path': '/home/user/.ssh/id_rsa'
},
{
'fingerprint_sha256': 'SHA256:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB',
'encrypted': False,
'fingerprint_md5': '11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11',
'path': '/home/user2/.ssh/id_rsa'
}
],
'agent': 'key-host.mozilla.com',
}
}
}

# This alert is the expected result from running this task
default_alert = {
'category': 'sshkey',
'severity': 'WARNING',
'summary': 'Private keys detected on key-host.mozilla.com missing from whitelist',
'tags': ['sshkey'],
}

test_cases = []

test_cases.append(
PositiveAlertTestCase(
description='Positive test case with good event',
events=[AlertTestSuite.create_event(default_event)],
expected_alert=default_alert
)
)

event = AlertTestSuite.create_event(default_event)
event['_type'] = 'audit'
test_cases.append(
NegativeAlertTestCase(
description="Negative test case with bad event type",
events=[event],
)
)

event = AlertTestSuite.create_event(default_event)
event['_source']['details']['agent'] = 'somehost.ignorehosts.com'
event['_source']['details']['private'] = [
{
'fingerprint_sha256': 'SHA256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
'encrypted': False,
'fingerprint_md5': '00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00',
'path': '/home/user/.ssh/id_rsa'
}
]
test_cases.append(
NegativeAlertTestCase(
description='Whitelist test with default configuration file',
events=[event],
)
)

event = AlertTestSuite.create_event(default_event)
event['_source']['details']['agent'] = 'somehost.ignorehosts.com'
event['_source']['details']['private'] = [
{
'fingerprint_sha256': 'SHA256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
'encrypted': False,
'fingerprint_md5': '00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00',
'path': '/home/user2/.ssh/id_rsa'
}
]
specific_alert = default_alert.copy()
specific_alert['summary'] = 'Private keys detected on somehost.ignorehosts.com missing from whitelist'
test_cases.append(
PositiveAlertTestCase(
description='Whitelist test with default configuration file, only host matches',
events=[event],
expected_alert=specific_alert
)
)

0 comments on commit 3f8a733

Please sign in to comment.