diff --git a/agent_based/cve_2021_44228_log4j.py b/agent_based/cve_2021_44228_log4j.py index 58038823aaaa59c491fed05b400055e9457b0d86..514717483362c7837da4fe8c1dc68c3308fb805a 100644 --- a/agent_based/cve_2021_44228_log4j.py +++ b/agent_based/cve_2021_44228_log4j.py @@ -29,6 +29,8 @@ # changed defaults for WARN/CRIT of affected files form (1, 1) to (None, None) # added Description/Comment to service details # 2022-02-05: fixed missing comment in CVE data (THX to doc[at]snowheaven[dot]de) +# 2022-02-07: added state_not_fixed option for per cve plugin +# 2022-02-14: added files_safe counter # # sample agent output @@ -91,6 +93,7 @@ class CVE_2021_44228_log4j: files_vulnerable: Optional[int] files_potential_vulnerable: Optional[int] files_mitigated: Optional[int] + files_safe: Optional[int] files_scanned: Optional[int] files_skipped: Optional[int] directories_scanned: Optional[int] @@ -305,6 +308,7 @@ def parse_cve_2021_44228_log4j(string_table: StringTable) -> CVE_2021_44228_log4 scanner_version = None files_vulnerable = None files_potential_vulnerable = None + files_safe = 0 files_mitigated = None files_scanned = None directories_scanned = None @@ -350,12 +354,15 @@ def parse_cve_2021_44228_log4j(string_table: StringTable) -> CVE_2021_44228_log4 errors += 1 elif line[:3] in ['[*]', '[?]']: cves = _parse_cves(cves, line) + elif line.startswith('[-] Found safe'): + files_safe += 1 return CVE_2021_44228_log4j( scanner_version=scanner_version, files_vulnerable=files_vulnerable, files_potential_vulnerable=files_potential_vulnerable, files_mitigated=files_mitigated, + files_safe=files_safe, files_scanned=files_scanned, files_skipped=files_skipped, directories_scanned=directories_scanned, @@ -407,6 +414,7 @@ def check_cve_2021_44228_log4j(params, section: CVE_2021_44228_log4j) -> CheckRe (section.files_vulnerable, 'Files vulnerable', 'files_vulnerable', False, params['files_vulnerable'], None), (section.files_potential_vulnerable, 'Files potentially vulnerable', 'files_potential_vulnerable', False, params['files_potential_vulnerable'], None), (section.files_mitigated, 'Files mitigated', 'files_mitigated', True, params['files_mitigated'], None), + (section.files_safe, 'Files safe', 'files_safe', True, None, None), (section.files_skipped, 'Files skipped', 'files_skipped', True, params['files_skipped'], None), (section.errors, 'Errors', 'errors', True, params['errors'], None), (section.files_scanned, 'Files scanned', 'files_scanned', True, params['files_scanned'].get('upper'), params['files_scanned'].get('lower')), @@ -729,7 +737,7 @@ def check_cve_2021_44228_log4j_cves(item, params, section: Dict) -> CheckResult: if cve['cve'].get('fixed'): yield Result(state=State.OK, summary=f'Fixed in: {", ".join(cve["cve"]["fixed"])}') else: - yield Result(state=State.WARN, summary=f'not fixed') + yield Result(state=State(params['state_not_fixed']), summary=f'not fixed') if cve['cve'].get('description'): yield Result(state=State.OK, notice=f'\n{cve["cve"]["description"]}') @@ -758,6 +766,7 @@ register.check_plugin( check_default_parameters={ 'files_affected': (None, None), 'cvss_score': (0.1, 5.5), + 'state_not_fixed': 1, 'state_not_found': 3, }, check_ruleset_name='cve_2021_44228_log4_cves', diff --git a/agents/bakery/cve_2021_44228_log4j.py b/agents/bakery/cve_2021_44228_log4j.py index b57840bcb100f69c444ac0b986975665b79ed4de..627185003ab4b38f6c3ec020bad5bf9e1507cb63 100755 --- a/agents/bakery/cve_2021_44228_log4j.py +++ b/agents/bakery/cve_2021_44228_log4j.py @@ -24,19 +24,31 @@ # 2022-01-30: added option --throttle # 2022-02-05: added option -xmx # removed options --force-fix, --backup-path +# 2022-02-13: added options --api-key and --http-proxy +# 2022-02-24: removed deployment of the logpresso executable -> separate package log4j_executable.mkp +# optimised code for config file generation from pathlib import Path from typing import List +from cmk.base.cee.plugins.bakery.bakery_api.v1 import ( + FileGenerator, + OS, + Plugin, + PluginConfig, + register, +) +from cmk.utils import ( + password_store, +) -from cmk.base.cee.plugins.bakery.bakery_api.v1 import FileGenerator, OS, Plugin, PluginConfig, register - - -bakery_version = '20220130.v0.1.1' +bakery_version = '20220307.v0.1.2' def get_cve_2021_44228_log4j_files(conf: List[any]) -> FileGenerator: options = conf[1].copy() - + _os = '' + _plugin_source = '' + _plugin_target = '' options_array: List = [] search_path_array: List = [] separator: str = ' ' # needs matching separator in the shell scripts @@ -60,8 +72,14 @@ def get_cve_2021_44228_log4j_files(conf: List[any]) -> FileGenerator: if conf[0] == 'linux': config_path = '/etc/check_mk/' + _os = OS.LINUX + _plugin_source = 'cve_2021_44228_log4j.linux' + _plugin_target = 'cve_2021_44228_log4j.sh' elif conf[0] == 'windows': config_path = 'C:\\ProgramData\\checkmk\\agent\\config\\' + _os = OS.WINDOWS + _plugin_source = 'cve_2021_44228_log4j.windows' + _plugin_target = 'cve_2021_44228_log4j.ps1' if options['search_in'] == 'all_drives': options_array.append('--all-drives') @@ -118,6 +136,17 @@ def get_cve_2021_44228_log4j_files(conf: List[any]) -> FileGenerator: # options_array.append(f'--no-empty-report') # will not report on errors/skipped only findings (no files section) options.pop('reporting') + if options.get('logpresso_watch'): + if options['logpresso_watch']['api_key'][0] == 'store': + api_key = password_store.extract(options['logpresso_watch']['api_key'][1]) + else: + api_key = options['logpresso_watch']['api_key'][1] + options_array.append(f'--api-key {api_key}') + if options['logpresso_watch'].get('http_proxy'): + http_proxy, proxy_port = options['logpresso_watch']['http_proxy'] + options_array.append(f'--http-proxy {http_proxy}:{proxy_port}') + options.pop('logpresso_watch') + if options.get('append_to_log'): log_file = options['append_to_log']['log_path_file'] log_format = options['append_to_log'].get('report_format', '--csv-log-path') @@ -168,107 +197,54 @@ def get_cve_2021_44228_log4j_files(conf: List[any]) -> FileGenerator: options = separator.join(options_array) options = f'{options}{separator}{search_path}' - if conf[0] == 'linux': - yield Plugin( - base_os=OS.LINUX, - source=Path('cve_2021_44228_log4j.linux'), - target=Path('cve_2021_44228_log4j.sh'), - asynchronous=True, - interval=interval, - timeout=timeout, - ) - yield Plugin( - base_os=OS.LINUX, - source=Path('log4j2-scan.linux'), - target=Path('../bin/log4j2-scan'), + yield Plugin( + base_os=_os, + source=Path(_plugin_source), + target=Path(_plugin_target), + asynchronous=True, + interval=interval, + timeout=timeout, + ) + + if _os == OS.LINUX: + options = f'({options});' + + yield PluginConfig( + base_os=_os, + lines=[ + f'BAKERY_VERSION={bakery_version}', + f'OPTIONS={options}', + f'PLUGIN_TIMEOUT={timeout}', + f'ATTACH_REPORT={attach_report_to_output}', + ], + target=Path('cve_2021_44228_log4j.cfg'), + include_header=True, + ) + + if include_paths: + yield PluginConfig( + base_os=_os, + lines=[include_paths], + target=Path('cve_2021_44228_log4j_search.cfg'), + include_header=False, ) + if exclude_paths: yield PluginConfig( - base_os=OS.LINUX, - lines=[ - f'BAKERY_VERSION={bakery_version}', - f'OPTIONS=({options});', - f'PLUGIN_TIMEOUT={timeout}', - f'ATTACH_REPORT={attach_report_to_output}', - ], - target=Path('cve_2021_44228_log4j.cfg'), - include_header=True, + base_os=_os, + lines=[exclude_paths], + target=Path('cve_2021_44228_log4j_exclude.cfg'), + include_header=False, ) - if include_paths: - yield PluginConfig( - base_os=OS.LINUX, - lines=[include_paths], - target=Path('cve_2021_44228_log4j_search.cfg'), - include_header=False, - ) - - if exclude_paths: - yield PluginConfig( - base_os=OS.LINUX, - lines=[exclude_paths], - target=Path('cve_2021_44228_log4j_exclude.cfg'), - include_header=False, - ) - - if exclude_files: - yield PluginConfig( - base_os=OS.LINUX, - lines=[exclude_files], - target=Path('cve_2021_44228_log4j_exclude_files.cfg'), - include_header=False, - ) - - elif conf[0] == 'windows': - yield Plugin( - base_os=OS.WINDOWS, - source=Path('cve_2021_44228_log4j.windows'), - target=Path('cve_2021_44228_log4j.ps1'), - asynchronous=True, - interval=interval, - timeout=timeout + 20, # moved timeout handling to the ps script, keep this to be safe - ) - yield Plugin( - base_os=OS.WINDOWS, - source=Path('log4j2-scan.windows'), - target=Path('..\\bin\\log4j2-scan.exe'), - ) + if exclude_files: yield PluginConfig( - base_os=OS.WINDOWS, - lines=[ - f'BAKERY_VERSION={bakery_version}', - f'OPTIONS={options}', - f'PLUGIN_TIMEOUT={timeout}', - f'ATTACH_REPORT={attach_report_to_output}', - ], - target=Path('cve_2021_44228_log4j.cfg'), - include_header=True, + base_os=_os, + lines=[exclude_files], + target=Path('cve_2021_44228_log4j_exclude_files.cfg'), + include_header=False, ) - if include_paths: - yield PluginConfig( - base_os=OS.WINDOWS, - lines=[include_paths], - target=Path('cve_2021_44228_log4j_search.cfg'), - include_header=False, - ) - - if exclude_paths: - yield PluginConfig( - base_os=OS.WINDOWS, - lines=[exclude_paths], - target=Path('cve_2021_44228_log4j_exclude.cfg'), - include_header=False, - ) - - if exclude_files: - yield PluginConfig( - base_os=OS.WINDOWS, - lines=[exclude_files], - target=Path('cve_2021_44228_log4j_exclude_files.cfg'), - include_header=False, - ) - register.bakery_plugin( name='cve_2021_44228_log4j', diff --git a/agents/plugins/cve_2021_44228_log4j.cfg.linux b/agents/plugins/cve_2021_44228_log4j.cfg.linux old mode 100644 new mode 100755 diff --git a/agents/plugins/cve_2021_44228_log4j.cfg.windows b/agents/plugins/cve_2021_44228_log4j.cfg.windows old mode 100644 new mode 100755 diff --git a/cve_2021_44228_log4j.mkp b/cve_2021_44228_log4j.mkp index 951be024e36156317a1223c555261bf7bd910134..ed2a6a69baff2808663603c80c1c413ada7cf6c9 100644 Binary files a/cve_2021_44228_log4j.mkp and b/cve_2021_44228_log4j.mkp differ diff --git a/packages/cve_2021_44228_log4j b/packages/cve_2021_44228_log4j index 02381e58875cafcf8f56a84c1752470aeae1eae0..6c36620098ed44b0c444c58127597015b68d34ff 100644 --- a/packages/cve_2021_44228_log4j +++ b/packages/cve_2021_44228_log4j @@ -1,5 +1,10 @@ {'author': 'Th.L. (thl-cmk[at]outlook[dot]com)', 'description': 'CVE-2921-44228-log4j discovery\n' + '\n' + '\n' + 'NOTE: the logpresso executables are no longer part of this ' + 'package. Please use the separate package ' + '"log4j_executable.mkp" to deploy the scanner.\n' '\n' 'This plugin discovers vulnerable files for the ' 'CVE-2921-44228-log4j \n' @@ -23,17 +28,15 @@ 'agents': ['bakery/cve_2021_44228_log4j.py', 'plugins/cve_2021_44228_log4j.linux', 'plugins/cve_2021_44228_log4j.windows', - 'plugins/log4j2-scan.linux', - 'plugins/log4j2-scan.windows', 'plugins/cve_2021_44228_log4j.cfg.linux', 'plugins/cve_2021_44228_log4j.cfg.windows'], 'web': ['plugins/metrics/cve_2021_44228_log4j.py', 'plugins/wato/cve_2021_44228_log4j.py', 'plugins/views/inv_cve_2021_22448_log4j.py']}, 'name': 'cve_2021_44228_log4j', - 'num_files': 11, + 'num_files': 9, 'title': 'CVE-2021-44228-log4j scanner plugin', - 'version': '20220205.v0.1.2', + 'version': '20220309.v0.1.4', 'version.min_required': '2.0.0', 'version.packaged': '2021.09.20', 'version.usable_until': None} \ No newline at end of file diff --git a/web/plugins/metrics/cve_2021_44228_log4j.py b/web/plugins/metrics/cve_2021_44228_log4j.py index 39f4ca513546a3fee6a6bc76232a3b8cc2a84e48..e1fefb65edd6ed7c9e81ab457836614ddee993c4 100644 --- a/web/plugins/metrics/cve_2021_44228_log4j.py +++ b/web/plugins/metrics/cve_2021_44228_log4j.py @@ -11,7 +11,8 @@ # # 2021-12-20: added run time to the perfometer # 2022-01-25: added metrics/graph/perfometer for files_affected - +# 2022-02-14: added files_safe +# from cmk.gui.i18n import _ from cmk.gui.plugins.metrics import ( @@ -37,6 +38,11 @@ metric_info['files_mitigated'] = { 'color': '31/a', } +metric_info['files_safe'] = { + 'title': _('Safe'), + 'unit': 'count', + 'color': '33/a', +} metric_info['files_skipped'] = { 'title': _('Skipped'), 'unit': 'count', @@ -74,6 +80,7 @@ graph_info['cve_2021_44228_log4j_found'] = { 'metrics': [ ('files_mitigated', '-stack'), ('files_skipped', '-stack'), + ('files_safe', 'stack'), ('files_potential_vulnerable', 'stack'), ('files_vulnerable', 'stack'), ], diff --git a/web/plugins/wato/cve_2021_44228_log4j.py b/web/plugins/wato/cve_2021_44228_log4j.py index 057470e6663cd84db99f114fd57f4253d7fd9280..34bbea9824b730ed05a689da3414c5fea10ac175 100644 --- a/web/plugins/wato/cve_2021_44228_log4j.py +++ b/web/plugins/wato/cve_2021_44228_log4j.py @@ -31,6 +31,12 @@ # scan_logback and log4j_1 enabled by default for new agent plugin rules # 2022-02-05: added option -Xmx # removed options --force-fix and --backup-path +# 2022-02-07: added state_not_fixed option for per cve plugin +# changed CVSS score from Integer to Float +# 2022-02-13: added option "Use logpresse log watch" (--api-key/--http-proxy") +# 2022-02-14: added option "Report safe files" (--report-patch) +# removed "Use logpresse log watch" and "Report fixed" from windows options, need to stay with pre 3.0.0 +# scanner version (3.0.0 and up are to large for the installer :-() # from cmk.gui.i18n import _ @@ -59,6 +65,9 @@ from cmk.gui.plugins.wato import ( CheckParameterRulespecWithItem, HostRulespec, ) +from cmk.gui.plugins.wato.utils import ( + PasswordFromStore, +) from cmk.gui.plugins.wato.inventory import ( RulespecGroupInventory, @@ -72,7 +81,7 @@ from cmk.gui.cee.plugins.wato.agent_bakery.rulespecs.utils import ( RulespecGroupMonitoringAgentsAgentPlugins, ) -bakery_plugin_version = '20220205.v0.0.9' +bakery_plugin_version = '20220309.v0.1.1' # ######################################################################################################### # @@ -86,6 +95,7 @@ _items_on_info = [ ('files_mitigated', 'Files mitigated'), ('files_scanned', 'Files scanned'), ('files_skipped', 'Files skipped'), + ('files_safe', 'Files safe'), ('directories_scanned', 'Directories scanned'), ('run_time', 'Run time'), ('last_run', 'Last run'), @@ -243,8 +253,8 @@ def _valuespec_cve_2021_44228_log4_cves(): title=_('CVSS score'), help=_('Upper levels for CVSS score.'), elements=[ - Integer(title=_('Warning at'), minvalue=0, unit=_('CVSS score'), default_value=0.1), - Integer(title=_('Critical at'), minvalue=0, unit=_('CVSS score'), default_value=5.5), + Float(title=_('Warning at'), minvalue=0, unit=_('CVSS score'), default_value=0.1), + Float(title=_('Critical at'), minvalue=0, unit=_('CVSS score'), default_value=5.5), ])), ('files_affected', Tuple( @@ -254,6 +264,14 @@ def _valuespec_cve_2021_44228_log4_cves(): Integer(title=_('Warning at'), minvalue=0, unit=_('Files'), default_value=10), Integer(title=_('Critical at'), minvalue=0, unit=_('Files'), default_value=30), ])), + ('state_not_fixed', + MonitoringState( + default_value=1, + title=_('State on no fixed version available'), + help=_( + 'Monitoring state if for an CVE no fixed version is available (not fixed). Default is Warn.' + ) + )), ('state_not_found', MonitoringState( default_value=3, @@ -389,6 +407,45 @@ _base_options_config_fix_files = ( ) +_base_options_config_logpresso_watch = ( + 'logpresso_watch', + Dictionary( + title=_('Use Logpresso watch'), + elements=[ + ('api_key', + PasswordFromStore( + title=_('Logpresso watch API key'), + allow_empty=False, + help=_( + 'Your API key to use logpresso watch. See https://logpresso.watch/.' + 'Implements the "--api-key" option.' + ), + + )), + ('http_proxy', + Tuple( + title=_('Use a http proxy server'), + elements=[ + TextUnicode( + label=_('Proxy server name/IP-Address'), + help=_( + 'Name or IP-address of the proxy server. Implements the "--http-proxy" option.' + ), + allow_empty=False, + ), + Integer( + label=_('Proxy server port'), + default_value=3128, + minvalue=1, + maxvalue=65565, + ), + ], + )), + ], + required_keys=['api_key'], + ), +) + _base_options_config_interval = ( 'interval', Integer( @@ -493,6 +550,19 @@ _base_options_config_silent = ( ) ) +_base_options_config_report_patch = ( + 'report_patch', + FixedValue( + '--report-patch', + title=_('Report safe files'), + totext=_('Report safe files enabled'), + help=_( + 'Report also patched/fixed/not vulnerable log4j files. Implements the "--report-patch" option.' + ), + ) +) + + _base_option_config_exclude_fs = ( 'exclude_fs', ListOfStrings( @@ -846,7 +916,9 @@ def _valuespec_agent_config_cve_2021_44228_log4j(): _base_option_config_exclude_fs, _base_options_config_no_symlink, _base_option_config_syslog, + _base_options_config_report_patch, _base_option_config_report, + _base_options_config_logpresso_watch, _base_option_append_to_log, _base_options_config_silent, _base_options_config_interval, @@ -857,7 +929,7 @@ def _valuespec_agent_config_cve_2021_44228_log4j(): # _base_options_config_trace, # run takes to long, produces to much output ], required_keys=['search_in'], - default_keys=['scan_logback', 'log4j_1', 'silent', 'reporting'], + default_keys=['scan_logback', 'log4j_1', 'silent', 'reporting', 'report_patch'], )), ('windows', _('Deploy Windows CVE-2021-44228-log4j agent plugin'), @@ -917,7 +989,9 @@ def _valuespec_agent_config_cve_2021_44228_log4j(): # _base_option_config_exclude_fs, # filesystem type on windows? # _base_options_config_no_symlink, # sym links on windows? _base_option_config_syslog, + _base_options_config_report_patch, _base_option_config_report, + _base_options_config_logpresso_watch, _base_option_append_to_log, _base_options_config_silent, _base_options_config_interval,