~arx10/furemcape unlisted

ref: 2a16b9d559ea1d81195b8b09bf42ddfe5e9a3d5f furemcape/transformer/furemcape/transformer/processor/open_sshd_parser.py -rw-r--r-- 4.0 KiB
2a16b9d5Justin Ludwig relax execmem restrictions for feeder service tls 10 months ago
                                                                                        
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# -*- coding: utf-8 -*-
"""Processor that parses OpenSSH sshd log messages into hitdb-ready properties."""

import re
from logging import getLogger

from .base_processor import BaseProcessor

MESSAGES = [
    re.compile(r"(?P<error>Invalid user) (?P<user>.*?) from (?P<ip>\S+)"),
    re.compile(
        r"(?P<action>input_userauth_request): (?P<error>invalid user) (?P<user>.*)"
    ),
    re.compile(
        r"(?:error: )?(?P<action>Received disconnect)"
        r" from (?P<ip>\S+) port \d+:\d+: (?P<error>.+)?"
    ),
    re.compile(
        r"(?P<action>Starting session): (?P<resource>.+?)"
        r" for (?P<user>.+?) from (?P<ip>\S+)"
    ),
    re.compile(r"(?P<error>Did not receive identification string) from (?P<ip>\S+)"),
    re.compile(r"(?P<action>(?:Connection|Disconnected)) from (?P<ip>\S+)"),
    re.compile(
        r"(?P<action>(?:Accepted|Failed) publickey) for (?P<user>.+?)"
        r" from (?P<ip>\S+) port \d+ \S+: (?P<resource>.+)"
    ),
    re.compile(
        r"pam_unix.sshd:session.: (?P<action>session (?:opened|closed))"
        r" for user (?P<user>\S+)"
    ),
    re.compile(r"(?P<action>Closing connection) to (?P<ip>\S+)"),
    re.compile(r"(?P<action>Close session): user (?P<user>.+?) from (?P<ip>\S+)"),
    re.compile(
        r"error: (?P<error>maximum authentication attempts exceeded)"
        r" for (invalid user )?(?P<user>.+?) from (?P<ip>\S+)"
    ),
    re.compile(r"(?P<error>Bad protocol version .+?) from (?P<ip>\S+)"),
    re.compile(r"(?P<action>Disconnecting): (?P<error>.+)"),
    re.compile(r"(?P<action>Connection (?:reset|closed)) by (?P<ip>\S+)"),
    re.compile(
        r"fatal: (?P<action>Unable to negotiate)"
        r" with (?P<ip>\S+) port \d+: (?P<error>.+?)."
        r" Their offer: (?P<resource>.+)"
    ),
    re.compile(r"(?P<action>Read error) from remote host (?P<ip>\S+): (?P<error>.+)"),
    re.compile(r"(?P<action>Postponed publickey) for (?P<user>.+?) from (?P<ip>\S+)"),
    re.compile(r"(?P<action>(?:Transferred|User child))[: ]"),
]


class OpenSshdParser(BaseProcessor):
    """Processor that parses OpenSSH sshd log messages into hitdb-ready properties."""

    LOG = getLogger(__name__)

    def __init__(self, property="message", ignore_missing=False):  # noqa: A002
        """Creates new processor.

        Arguments:
            property (str): Log-data property to parse (defaults to 'message').
            ignore_missing (str): True to suppress errors when property is missing
                (defaults to False).
        """
        self.property = property
        self.ignore_missing = ignore_missing

    # complexity is high, but still fairly readable
    def process(self, data):  # noqa: CCR001
        """Processes the specified log-entry data.

        Arguments:
            data (dict): Dict of log-entry data.

        Returns:
            dict: Updated dict of log-entry data.

        Raises:
            KeyError: Configured property not in specified data.
        """
        if not self.ignore_missing and self.property not in data:
            raise KeyError("missing {} property: {}".format(self.property, data))

        message = data.get(self.property)
        if not message:
            return data

        # strip [preauth] from end of message
        preauth = False
        if message.endswith(" [preauth]"):
            message = message[:-10]
            preauth = True

        for pattern in MESSAGES:
            match = pattern.match(message)
            if match:
                break

        if not match:
            self.LOG.warning("opensshd message not matched: %s", message)
            return data

        groupdict = match.groupdict("")
        data.update(groupdict)

        # normalize action and error
        _lowercase_first_letter(data, "action")
        _lowercase_first_letter(data, "error")

        # add [preauth] to action if present
        if preauth and "action" in groupdict:
            data["action"] += " [preauth]"

        return data


def _lowercase_first_letter(data, key):
    value = data.get(key, "")
    if value:
        data[key] = value[0].lower() + value[1:]