зеркало из https://github.com/mozilla/MozDef.git
Merge pull request #490 from mpurzynski/normalization_auth
Normalization auth
This commit is contained in:
Коммит
f7834f79d2
|
@ -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)
|
|
@ -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'
|
Загрузка…
Ссылка в новой задаче