Merge pull request #490 from mpurzynski/normalization_auth

Normalization auth
This commit is contained in:
A Smith 2017-10-12 11:00:17 -05:00 коммит произвёл GitHub
Родитель 3f97a66a24 fa67e3d5d7
Коммит f7834f79d2
4 изменённых файлов: 497 добавлений и 0 удалений

67
mq/plugins/parse_sshd.py Normal file
Просмотреть файл

@ -0,0 +1,67 @@
# 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:
# Michal Purzynski mpurzynski@mozilla.com
import sys
import os
import re
sys.path.append(os.path.join(os.path.dirname(__file__), "../../lib"))
from utilities.toUTC import toUTC
class message(object):
def __init__(self):
'''
takes an incoming sshd message
and sets the doc_type
'''
self.registration = ['sshd']
self.priority = 5
def onMessage(self, message, metadata):
self.accepted_regex = re.compile('^(?P<authstatus>\w+) (?P<authmethod>\w+) for (?P<username>[a-zA-Z0-9\@._-]+) from (?P<sourceipaddress>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) port (?P<sourceport>\d{1,5}) ssh2(\:\sRSA\s)?(?:(?P<rsakeyfingerprint>(\w+\:){15}\w+))?$')
self.session_opened_regex = re.compile('^pam_unix\(sshd\:session\)\: session (opened|closed) for user (?P<username>[a-zA-Z0-9\@._-]+)(?: by \(uid\=\d*\))?$')
self.postponed_regex = re.compile('^Postponed (?P<authmethod>\w+) for (?P<username>[a-zA-Z0-9\@._-]+) from (?P<sourceipaddress>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) port (?P<sourceport>\d{1,5}) ssh2(?: \[preauth\])?$')
self.starting_session_regex = re.compile('^Starting session: (?P<sessiontype>\w+)(?: on )?(?P<device>pts/0)? for (?P<username>[a-zA-Z0-9\@._-]+) from (?P<sourceipaddress>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) port (?P<sourceport>\d{1,5})$')
self.session_closed_regex = re.compile('^pam_unix\(sshd\:session\)\: session closed for user (?P<username>[a-zA-Z0-9\@._-]+)$')
if 'details' in message:
if 'program' in message['details']:
if message['details']['program'] == 'sshd':
msg_unparsed = message['summary']
if msg_unparsed.startswith('Accepted'):
accepted_search = re.search(self.accepted_regex, msg_unparsed)
if accepted_search:
message['details']['authstatus'] = accepted_search.group('authstatus')
message['details']['authmethod'] = accepted_search.group('authmethod')
message['details']['username'] = accepted_search.group('username')
message['details']['sourceipaddress'] = accepted_search.group('sourceipaddress')
message['details']['sourceport'] = accepted_search.group('sourceport')
message['details']['rsakeyfingerprint'] = accepted_search.group('rsakeyfingerprint')
if msg_unparsed.startswith('pam_unix'):
session_opened_search = re.search(self.session_opened_regex, msg_unparsed)
if session_opened_search:
message['details']['username'] = session_opened_search.group('username')
if msg_unparsed.startswith('Postponed'):
postponed_search = re.search(self.postponed_regex, msg_unparsed)
if postponed_search:
message['details']['username'] = postponed_search.group('username')
message['details']['authmethod'] = postponed_search.group('authmethod')
if msg_unparsed.startswith('Starting session'):
starting_session_search = re.search(self.starting_session_regex, msg_unparsed)
if starting_session_search:
message['details']['sessiontype'] = starting_session_search.group('sessiontype')
message['details']['username'] = starting_session_search.group('username')
message['details']['sourceipaddress'] = starting_session_search.group('sourceipaddress')
message['details']['sourceport'] = starting_session_search.group('sourceport')
message['details']['device'] = starting_session_search.group('device')
return (message, metadata)

43
mq/plugins/parse_su.py Normal file
Просмотреть файл

@ -0,0 +1,43 @@
# 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:
# Michal Purzynski mpurzynski@mozilla.com
import sys
import os
import re
sys.path.append(os.path.join(os.path.dirname(__file__), "../../lib"))
class message(object):
def __init__(self):
'''
takes an incoming sshd message
and sets the doc_type
'''
self.registration = ['sshd']
self.priority = 5
def onMessage(self, message, metadata):
self.session_regexp = re.compile('^pam_unix\(su(?:-l)?\:session\)\: session (?P<status>\w+) for user (?P<username>\w+)(?: (?:by (?:(?P<originuser>\w+))?\(uid\=(?P<uid>[0-9]+)\)?)?)?$')
if 'details' in message:
if 'program' in message['details']:
if message['details']['program'] == 'su':
msg_unparsed = message['summary']
if msg_unparsed.startswith('pam_unix'):
session_search = re.search(self.session_regexp, msg_unparsed)
if session_search:
message['details']['originuser'] = session_search.group('originuser')
message['details']['status'] = session_search.group('status')
message['details']['uid'] = session_search.group('uid')
message['details']['username'] = session_search.group('username')
return (message, metadata)

Просмотреть файл

@ -0,0 +1,248 @@
# 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:
# Michal Purzynski mpurzynski@mozilla.com
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), "../../../mq/plugins"))
from parse_sshd import message
import copy
accept_message = {}
accept_message['_type'] = 'event'
accept_message = {}
accept_message['utctimestamp'] = '2017-08-24T22:49:42+00:00'
accept_message['timestamp'] = '2017-08-24T22:49:42+00:00'
accept_message['receivedtimestamp'] = '2017-08-24T22:49:42+00:00'
accept_message['category'] = 'syslog'
accept_message['processid'] = '0'
accept_message['severity'] = '7'
accept_message['hostname'] = 'syslog1.private.scl3.mozilla.com'
accept_message['mozdefhostname'] = 'mozdef4.private.scl3.mozilla.com'
accept_message['eventsource'] = 'systemlogs'
accept_message['details'] = {}
accept_message['details']['processid'] = '5413'
accept_message['details']['Random'] = '9'
accept_message['details']['sourceipv4address'] = '10.22.74.208'
accept_message['details']['hostname'] = 'mysuperhost.somewhere.com'
accept_message['details']['program'] = 'sshd'
accept_message['details']['sourceipaddress'] = '10.22.74.208'
# Short username, RSA fpr present
class TestSSHDAcceptedMessageV1():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(accept_message)
self.msg['summary'] = 'Accepted publickey for user1 from 10.22.74.208 port 26388 ssh2: RSA 1f:c9:4c:90:bc:fb:72:c7:4d:02:da:07:ed:fe:07:ac'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['username'] == 'user1'
assert retmessage['details']['rsakeyfingerprint'] == '1f:c9:4c:90:bc:fb:72:c7:4d:02:da:07:ed:fe:07:ac'
assert retmessage['details']['authmethod'] == 'publickey'
assert retmessage['details']['sourceport'] == '26388'
assert retmessage['details']['authstatus'] == 'Accepted'
assert retmessage['details']['sourceipaddress'] == '10.22.74.208'
# Long username
class TestSSHDAcceptedMessageV2():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(accept_message)
self.msg['summary'] = 'Accepted publickey for user1@domainname.com from 10.22.74.208 port 26388 ssh2: RSA 1f:c9:4c:90:bc:fb:72:c7:4d:02:da:07:ed:fe:07:ac'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['username'] == 'user1@domainname.com'
assert retmessage['details']['rsakeyfingerprint'] == '1f:c9:4c:90:bc:fb:72:c7:4d:02:da:07:ed:fe:07:ac'
assert retmessage['details']['authmethod'] == 'publickey'
assert retmessage['details']['sourceport'] == '26388'
assert retmessage['details']['authstatus'] == 'Accepted'
assert retmessage['details']['sourceipaddress'] == '10.22.74.208'
# Short username, RSA fpr missing
class TestSSHDAcceptedMessageV3():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(accept_message)
self.msg['summary'] = 'Accepted publickey for user1 from 10.22.74.208 port 26388 ssh2'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['username'] == 'user1'
assert retmessage['details']['rsakeyfingerprint'] is None
assert retmessage['details']['authmethod'] == 'publickey'
assert retmessage['details']['sourceport'] == '26388'
assert retmessage['details']['authstatus'] == 'Accepted'
assert retmessage['details']['sourceipaddress'] == '10.22.74.208'
# PAM session opened for user
class TestSSHDPAMSessionOpenedMessageV1():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(accept_message)
self.msg['summary'] = 'pam_unix(sshd:session): session opened for user user1 by (uid=0)'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['username'] == 'user1'
# PAM session closed for user
class TestSSHDPAMSessionClosedMessageV1():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(accept_message)
self.msg['summary'] = 'pam_unix(sshd:session): session closed for user user1'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['username'] == 'user1'
# Postponed preauth - short, simple username
class TestSSHDPostponedMessageV1():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(accept_message)
self.msg['summary'] = 'Postponed publickey for user1 from 10.22.75.209 port 37486 ssh2'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['username'] == 'user1'
assert retmessage['details']['authmethod'] == 'publickey'
# Postponed preauth - long, simple username
class TestSSHDPostponedMessageV2():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(accept_message)
self.msg['summary'] = 'Postponed publickey for user1 from 10.22.75.209 port 37486 ssh2 [preauth]'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['username'] == 'user1'
assert retmessage['details']['authmethod'] == 'publickey'
# Postponed preauth - long username
class TestSSHDPostponedMessageV3():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(accept_message)
self.msg['summary'] = 'Postponed publickey for user1@somewhere.com from 10.22.75.209 port 37486 ssh2 [preauth]'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['username'] == 'user1@somewhere.com'
assert retmessage['details']['authmethod'] == 'publickey'
# Starting session
class TestSSHDStartingSessionV1():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(accept_message)
self.msg['summary'] = 'Starting session: command for user1 from 10.22.128.93 port 51748'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['username'] == 'user1'
assert retmessage['details']['sessiontype'] == 'command'
assert retmessage['details']['sourceipaddress'] == '10.22.128.93'
assert retmessage['details']['sourceport'] == '51748'
# Starting session
class TestSSHDStartingSessionV2():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(accept_message)
self.msg['summary'] = 'Starting session: shell on pts/0 for user2 from 10.22.252.6 port 59983'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['username'] == 'user2'
assert retmessage['details']['sessiontype'] == 'shell'
assert retmessage['details']['sourceipaddress'] == '10.22.252.6'
assert retmessage['details']['sourceport'] == '59983'
assert retmessage['details']['device'] == 'pts/0'

Просмотреть файл

@ -0,0 +1,139 @@
# 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:
# Michal Purzynski mpurzynski@mozilla.com
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), "../../../mq/plugins"))
from parse_su import message
import copy
session_su = {}
session_su['_type'] = 'event'
session_su = {}
session_su['utctimestamp'] = '2017-08-24T22:49:42+00:00'
session_su['timestamp'] = '2017-08-24T22:49:42+00:00'
session_su['receivedtimestamp'] = '2017-08-24T22:49:42+00:00'
session_su['category'] = 'syslog'
session_su['processid'] = '0'
session_su['severity'] = '7'
session_su['eventsource'] = 'systemlogs'
session_su['hostname'] = 'syslog1.private.scl3.mozilla.com'
session_su['mozdefhostname'] = 'mozdef4.private.scl3.mozilla.com'
session_su['details'] = {}
session_su['details']['Random'] = '9'
session_su['details']['program'] = 'su'
session_su['details']['hostname'] = 'irc1.dmz.scl3.mozilla.com'
class TestSuSessionOpenedMessageV1():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(session_su)
self.msg['summary'] = 'pam_unix(su:session): session opened for user user1 by (uid=0)'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['originuser'] is None
assert retmessage['details']['status'] == 'opened'
assert retmessage['details']['uid'] == '0'
assert retmessage['details']['username'] == 'user1'
#
class TestSuSessionOpenedMessageV2():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(session_su)
self.msg['summary'] = 'pam_unix(su:session): session opened for user user2 by user3(uid=0)'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['originuser'] == 'user3'
assert retmessage['details']['status'] == 'opened'
assert retmessage['details']['uid'] == '0'
assert retmessage['details']['username'] == 'user2'
#
class TestSuSessionOpenedMessageV3():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(session_su)
self.msg['summary'] = 'pam_unix(su-l:session): session opened for user user4 by (uid=0)'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['originuser'] is None
assert retmessage['details']['status'] == 'opened'
assert retmessage['details']['uid'] == '0'
assert retmessage['details']['username'] == 'user4'
#
class TestSuSessionOpenedMessageV4():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(session_su)
self.msg['summary'] = 'pam_unix(su-l:session): session opened for user user5 by user6(uid=0)'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['originuser'] == 'user6'
assert retmessage['details']['status'] == 'opened'
assert retmessage['details']['uid'] == '0'
assert retmessage['details']['username'] == 'user5'
#
class TestSuSessionClosedMessageV1():
def setup(self):
self.msgobj = message()
self.msg = copy.deepcopy(session_su)
self.msg['summary'] = 'pam_unix(su:session): session closed for user user7'
def test_onMessage(self):
metadata = {}
metadata['doc_type'] = 'event'
(retmessage, retmeta) = self.msgobj.onMessage(self.msg, metadata)
assert retmessage is not None
assert retmeta is not None
assert retmessage['details']['originuser'] is None
assert retmessage['details']['status'] == 'closed'
assert retmessage['details']['uid'] is None
assert retmessage['details']['username'] == 'user7'