diff --git a/CHANGELOG b/CHANGELOG index 9624b28e3681def644e25fe5fee2bc81eec470c2..3e5adf9373d488e84f7c1c4f564db81dc9305eeb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -48,3 +48,23 @@ CHECK fixed run_time missing on service info (THX to doc[at]snowheaven[dot]de) INVENTOR added inventory plugin and view for reporting/sorting/filering etc. 2022-01-11: fixed missing newline on plugin section header output in Linux script + added option to add json report to inventory +2022-01-12: CHECK: modified logpresso report time format to ISO861 +2022-01-14: INVENTORY: added params to inventory sections + BACKERY: reorganised append to log (--csv-log-path/--json-log-path) and add report to inventory options (-report-path) + WATO: moved append to log outside of enable reporting + WATO: removed reporting to file + AGENT: join output of json report into one line for json.loads + CHECK: added params to inventory sections + WATO: added options for per CVE check + WATO: changed display name (again) from 'CVE scanner for log4j (CVE-2021-44228-log4j)' to 'log4j CVE scanner (CVE-2021-44228-log4j)' + WATO: enabled 'attach_report_to_output' in "reporting" by default for new rules +2022-01-17: CHECK: added check plugin with CVE id as item +2022-01-18: extended inventory report for additional log4j CVEs + removed status_data inventory +2022-01-21: reworked report inventory plugin and per cve check +2022-01-22: Inventory view: added entry's for 'CVE-2021-42550' and 'CVE-2021-4104' +2022-01-25: BAKERY: added option --exclude-pattern + WATO: added option --exclude-pattern + METRICS: added metrics/graph/perfometer for files_affected + diff --git a/HOWTO.md b/HOWTO.md index bd6e9a75632c5eac9038d5ff2022d84a1e65d9c7..853074982f2ed0d2b2fb81be400515b9003cc2ff 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -37,7 +37,7 @@ plugins: If you are using certion plugin configurations the bakery will create some additional files in the configuration directory of the agenet. | WATO option | Scanner option | file | content | -| ------ | ------ | ------ | ------ | +| ------ | ------ | ------ | ------ | | Search path (bulk) | `-f` | `cve_2021_44228_log4j_search.cfg` | paths to search in seperated by newline | | Exclude paths (bulk) | `--exclude-config` | `cve_2021_44228_log4j_exclude.cfg` | path to exclude from the sarch seperated by newline | | Exclude files (bulk) | `--exclude-file-config` | `cve_2021_44228_log4j_exclude_files.cfg` | files exclude from the search seperated by newline | @@ -47,6 +47,7 @@ If you are using certion plugin configurations the bakery will create some addit </details> + <details><summary>Using a specific version of the scanner</summary> Included with this package are the scanner files for Linux and Windows in version 2.5.3 (2021-12-22). As the development of the scanner is still moving veriy fast forward, I will update the package from time to time. If you want to use a specific version of the scanner just put the files to `~/local/share/check_mk/agents/plugins` of your CMK site and redeploy the agent (bakery). @@ -168,7 +169,10 @@ Example config file for the Linux agent plugin # This file is managed via WATO, do not edit manually or you # lose your changes next time when you update the agent. -OPTIONS=(--exclude "/mnt" --exclude "/test with space" --exclude-fs nfs,fuse.vmhgfs-fuse --syslog-level debug --syslog-udp checkmk --scan-logback --scan-log4j1 --scan-zip --no-symlink --silent "/"); +BAKERY_VERSION=20220125.v0.1.0 +OPTIONS=(--exclude-fs nfs,cifs --report-path /var/log/log4j_report.json --report-json --exclude "/mnt" --exclude-file-config /etc/check_mk/cve_2021_44228_log4j_exclude_files.cfg --scan-logback --scan-log4j1 --scan-zip --no-symlink --silent /); +PLUGIN_TIMEOUT=300 +ATTACH_REPORT=/var/log/log4j_report.json ``` @@ -178,7 +182,10 @@ Example config file for the Windows agent plugin # This file is managed via WATO, do not edit manually or you # lose your changes next time when you update the agent. -OPTIONS=--all-drives --syslog-level debug --syslog-udp checkmk --report-dir "D:\Kannweg\reports" --report-json --scan-logback --scan-log4j1 --scan-zip --silent +BAKERY_VERSION=20220125.v0.1.0 +OPTIONS=--all-drives --report-path c:\windows\temp\log4j_report.json --report-json --exclude "D:\Kannweg\backups-1" --exclude-file-config C:\ProgramData\checkmk\agent\config\cve_2021_44228_log4j_exclude_files.cfg --scan-logback --scan-log4j1 --scan-zip --silent +PLUGIN_TIMEOUT=300 +ATTACH_REPORT=c:\windows\temp\log4j_report.json ``` @@ -322,4 +329,85 @@ Then you get this output </details> +<details><summary>Inventory plugins</summary> + +There are two inventory plugins +- CVE Scanner for log4j summary +- CVE Scanner for log4j report + +<details><summary>CVE Scanner for log4j summary</summary> + +"CVE Scanner for log4j summary" is enabled by default. This inventory plugin/view gives you an overview of the versions (scanner/script/bakery) used by all your hosts. Additional you get the used scan options and the statistics from the scanner. This plugin uses the same data as the check plugin "cve_2021_44228_log4j". The "CVE Scanner for log4j summary" can be disabled in the "Hardware / Software Inventory" rule "log4j CVE scanner (CVE-2021-44228-log4j)". + + + +</details> + +<details><summary>CVE Scanner for log4j report</summary> + +The second inventory plugin "CVE Scanner for log4j report" adds to all files reported by the logpresso scanner additional informations about several CVEs. This infromation is based solely on the log4j/logback version reported by the Logpresso scanner. To use this Inventory plugin you need to enable "Enable reporting" -> "Send report to checkmk" in the bakery rule. You can exclude scan errors from the inventory via the "Hardware / Software Inventory" rule "log4j CVE scanner (CVE-2021-44228-log4j)". + + + +</details> + +</details> + +<details><summary>Check plugin cve_2021_44228_log4j_cves</summary> + +There is an aditional check plugin `cve_2021_44228_log4j_cves`. This Plugin creates one service for each of the following CVEs: +- CVE-2021-44832 +- CVE-2021-45105 +- CVE-2021-45046 +- CVE-2021-44228 +- CVE-2021-42550 +- CVE-2020-9488 +- CVE-2017-5645 +- CVE-2021-4104 + +It wil then add all files affected by this CVE to the service. The information if a file is affected by a certain CVE is based solely on the log4j/logback version reported by the Logpresso scanner. If a file is affected doesn't mean this can be exploited. To use this check plugin you must enable "Enable reporting" -> "Send report to checkmk" in the bakery rule. In the discovery rule for this check plugin ("Service discovery rules" -> "log4j CVEs") you can enable to create a service also for CVEs without affected files. + + + +</details> + +<details><summary>Scanner options implemented in the bakery</summary> + + +| scanner option | bakery option | comment | +| ------ | ------ | ------ | +| target_path1 to n | Search method -> Search paths | +| -f [config_file_path] | Search method -> Search paths (bulk) | cve_2021_44228_log4j_search.cfg | +| --scan-log4j1 | Scan for log4j 1 versions (CVE-2021-4104) | +| --scan-logback | Scan for logback (CVE-2021-42550) | | +| --scan-zip | Scan zip files (increase timeout) | +| --force-fix | Fix files and backup -> Fix files. (Use at your own risk!) | +| --backup-path | Fix files and backup -> Backup directory (must exist) | +| --all-drives | Search method -> All drives | Windows only | +| --drives | Search method -> Drives to scan | Windows only | +| --no-symlink | Ignore symlinks | Linux only | +| --exclude [path_prefix] | Exclude paths -> Exclude paths -> Exclude paths | +| --exclude-config [config_file_path] | Exclude paths -> Exclude paths -> Exclude paths (bulk) | cve_2021_44228_log4j_exclude.cfg | +| --exclude-pattern [pattern] | Exclude paths -> Exclude paths by pattern | +| --exclude-file-config [config_file_path] | Exclude files (bulk) | cve_2021_44228_log4j_exclude_files.cfg | +| --exclude-fs | Exclude filesystems by type | +| --syslog-udp [host:port] | Enable syslog reporting -> Syslog server / Syslog server Port | +| --syslog-level [level] | Enable syslog reporting -> Loglevel | +| --syslog-facility [code] | Enable syslog reporting -> Facility | +| --rfc5424 | Enable syslog reporting -> Use RFC5424 syslog format | +| --report-csv | Enable reporting -> Enable file reporting -> Report format -> CSV | +| --report-json | Enable reporting -> Enable file reporting -> Report format -> JSON | +| --report-path | Enable reporting -> Send report to checkmk | log4j_report.json | +| --report-dir | Enable reporting -> Enable file reporting -> Report output directory (must exist) | +| --no-empty-report | Enable reporting -> Enable file reporting -> Don't create empty reports | +| --csv-log-path | Append results to log file -> Log file format -> CSV | +| --json-log-path | Append results to log file -> Log file format -> JSON | +| --silent | Silent output | +| --debug | Debug scanner | + +</details> + + + + </details> diff --git a/README.md b/README.md index 0c7438a7d67e350a58c6041f590943ecfbb4564b..f491641e0338fa5a241ec877321a126dc075a0f6 100644 --- a/README.md +++ b/README.md @@ -94,17 +94,27 @@ Nice ;-) Have a look at the [contribution guidelines](CONTRIBUTING.md "Contribut </details> -<details><summary>Sample inventory output</summary> +<details><summary>Sample inventory summary</summary> - + </details> +<details><summary>Sample inventory report</summary> + + + +</details> + </details> -<details><summary>WATO options check plugin</summary> - +<details><summary>WATO options</summary> + + +<details><summary>WATO check plugin</summary> + + </details> <details><summary>WATO bakery Linux</summary> @@ -118,3 +128,10 @@ Nice ;-) Have a look at the [contribution guidelines](CONTRIBUTING.md "Contribut  </details> + +<details><summary>WATO inventory</summary> + + + +</details> +</details> diff --git a/agent_based/cve_2021_44228_log4j.py b/agent_based/cve_2021_44228_log4j.py index b076ff8341c5dc026a6ec2e028ba8c9054c8fbd2..99617dfb212d963648e9f060db928d7fb496da42 100644 --- a/agent_based/cve_2021_44228_log4j.py +++ b/agent_based/cve_2021_44228_log4j.py @@ -20,6 +20,10 @@ # 2022-01-11: added inventory report section # 2022-01-12: modified logpresso report time format to ISO861 # 2022-01-14: added params to inventory sections +# 2022-01-17: added check plugin with CVE id as item +# 2022-01-18: extended inventory report for additional log4j CVEs +# removed status_data inventory +# 2022-01-21: reworked report inventory plugin and per cve check # # sample agent output @@ -48,7 +52,7 @@ # import json -from typing import Optional, Dict +from typing import Optional, Dict, List from dataclasses import dataclass from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( DiscoveryResult, @@ -68,6 +72,14 @@ from cmk.base.plugins.agent_based.agent_based_api.v1 import ( ) +@dataclass +class CVE: + files_vulnerable: int + files_potential_vulnerable: int + files_mitigated: int + files: List[str] + + @dataclass class CVE_2021_44228_log4j: scanner_version: Optional[str] @@ -84,12 +96,94 @@ class CVE_2021_44228_log4j: script_version: Optional[str] bakery_version: Optional[str] details: str + cves: Dict[str, CVE] + + +_log4_cves = { + 'Log4j 1': { + 'CVE-2021-4104': { + 'fixed': ['Apache Log4j 1.2 reached end of life in August 2015. Migrate to Log4j 2'], + 'excluded': [], + 'affected': '1.2.99', + 'cvss_score': 7.5, + 'Comment': 'Apache Log4j 1.2 reached end of life in August 2015. Migrate to Log4j 2' + }, + }, + 'Log4j 2': { + 'CVE-2021-44832': { + 'fixed': ['2.3.2', '2.12.4', '2.17.1'], + 'excluded': ['2.3.2', '2.12.4'], + 'affected': '2.17.0', + 'cvss_score': 6.6, + }, + 'CVE-2021-45105': { + 'fixed': ['2.3.1', '2.12.3', '2.17.0'], + 'excluded': ['2.12.3'], + 'affected': '2.16.0', + 'cvss_score': 5.9, + }, + 'CVE-2021-45046': { + 'fixed': ['2.3.1', '2.12.3', '2.17.0'], + 'excluded': ['2.12.2'], + 'affected': '2.15.0', + 'cvss_score': 9.0, + }, + 'CVE-2021-44228': { + 'fixed': ['2.3.1', '2.12.3', '2.17.0'], + 'excluded': [], + 'affected': '2.14.1', + 'cvss_score': 10.0, + }, + 'CVE-2020-9488': { + 'fixed': ['2.12.3', '2.13.2'], + 'excluded': [], + 'affected': '2.13.1', + 'cvss_score': 3.7, + }, + 'CVE-2017-5645': { + 'fixed': ['2.8.2'], + 'excluded': [], + 'affected': '2.8.1', + 'cvss_score': 7.5, + }, + }, + 'Logback': { + 'CVE-2021-42550': { + 'fixed': ['1.2.9'], + 'excluded': [], + 'affected': '1.2.7', + 'cvss_score': 6.6, + }, + }, +} + + +def _parse_cves(cves: Dict[str, CVE], line: str) -> Dict[str, CVE]: + split_line = line.split(' ') + cve = split_line[2] + + if cve not in cves.keys(): + cves[cve] = CVE( + files_vulnerable=0, + files_potential_vulnerable=0, + files_mitigated=0, + files=[] + ) + + if split_line[0] == '[*]': + cves[cve].files_vulnerable += 1 + elif split_line[0] == '[?]': + cves[cve].files_potential_vulnerable += 1 + if split_line[-1] == '(mitigated)': + cves[cve].files_mitigated += 1 + cves[cve].files.append(line) + + return cves def parse_cve_2021_44228_log4j(string_table: StringTable) -> CVE_2021_44228_log4j: details = '' last_run = string_table[0][0] - scanner_version = None files_vulnerable = None files_potential_vulnerable = None @@ -102,6 +196,7 @@ def parse_cve_2021_44228_log4j(string_table: StringTable) -> CVE_2021_44228_log4 scan_options = None script_version = None bakery_version = None + cves = {} for line in string_table: line = str(line[0]) @@ -135,6 +230,8 @@ def parse_cve_2021_44228_log4j(string_table: StringTable) -> CVE_2021_44228_log4 files_skipped += 1 elif line.lower().startswith('error: '): errors += 1 + elif line[:3] in ['[*]', '[?]']: + cves = _parse_cves(cves, line) return CVE_2021_44228_log4j( scanner_version=scanner_version, @@ -151,6 +248,7 @@ def parse_cve_2021_44228_log4j(string_table: StringTable) -> CVE_2021_44228_log4 script_version=script_version, bakery_version=bakery_version, details=details, + cves=cves, ) @@ -172,6 +270,12 @@ def parse_cve_2021_44228_log4j(string_table: StringTable) -> CVE_2021_44228_log4 # # +# ######################################################################################################### +# +# Check plugin for log4j CVE summary/main +# +# ######################################################################################################### + def discovery_cve_2021_44228_log4j(section: CVE_2021_44228_log4j) -> DiscoveryResult: yield Service() @@ -267,14 +371,14 @@ register.check_plugin( 'errors', 'files_skipped', ], - }, check_ruleset_name='cve_2021_44228_log4j' ) + # ######################################################################################################### # -# Inventory for CVE scanner for log4j (CVE-2021-44228-log4j) +# Inventory for CVE scanner for log4j (CVE-2021-44228-log4j) summary # # ######################################################################################################### @@ -287,18 +391,12 @@ def inventory_inv_cve_2021_44228_log4j(params, section: CVE_2021_44228_log4j) -> key_columns = {'index': '1'} inventory_columns = {} - status_columns = {} for key, value in [ ('scanner_version', section.scanner_version), ('scan_options', section.scan_options), ('script_version', section.script_version), ('bakery_version', section.bakery_version), - ]: - if value is not None: - inventory_columns.update({key: value}) - - for key, value in [ ('files_vulnerable', section.files_vulnerable), ('files_potential_vulnerable', section.files_potential_vulnerable), ('files_mitigated', section.files_mitigated), @@ -310,17 +408,12 @@ def inventory_inv_cve_2021_44228_log4j(params, section: CVE_2021_44228_log4j) -> ('errors', section.errors), ]: if value is not None: - status_columns.update({key: value}) - - if not params.get('do_status_data'): - inventory_columns.update(status_columns) - status_columns = {} + inventory_columns.update({key: value}) yield TableRow( path=path, key_columns=key_columns, inventory_columns=inventory_columns, - status_columns=status_columns ) @@ -330,7 +423,6 @@ register.inventory_plugin( inventory_function=inventory_inv_cve_2021_44228_log4j, inventory_ruleset_name='inventory_cve_2021_44228_log4j', inventory_default_parameters={ - 'do_status_data': False, 'do_not_inv_summary': False }, ) @@ -338,17 +430,105 @@ register.inventory_plugin( # ######################################################################################################### # -# Inventory for CVE scanner for log4j (CVE-2021-44228-log4j) +# Inventory for CVE scanner for log4j (CVE-2021-44228-log4j) report # # ######################################################################################################### +def _get_affected(version: str, affected: str) -> bool: + _version = version.split('.') + _affected = affected.split('.') + + if int(_version[0]) < int(_affected[0]): + return True + elif int(_version[0]) > int(_affected[0]): + return False + elif int(_version[1]) < int(_affected[1]): + return True + elif int(_version[1]) > int(_affected[1]): + return False + elif int(_version[2]) <= int(_affected[2]): + return True + + return False + + +def _add_log4j_cves(version: str, product: str) -> Dict[str, str]: + additional_cves = {} + + try: + cves = _log4_cves[product] + except KeyError: + return {} + + for cve in cves.keys(): + if version == 'N/A': + additional_cves[cve] = 'unknown, missing version' + elif (_get_affected(version, cves[cve]['affected']) is True) and (version not in cves[cve]['excluded']): + additional_cves[cve] = f'Affected, fixed in: {", ".join(cves[cve]["fixed"])}' + else: + additional_cves[cve] = 'not affected' + + return additional_cves + def parse_inv_cve_2021_44228_log4j_report(string_table: StringTable): + + def _get_ISO861_time(time_str: str) -> str: + return f'{time_str[:10]}T{time_str[11:22]}:{time_str[22:]}' # 2022-01-11T20:06:41+01:00 + try: section = json.loads(string_table[0][0]) except (json.decoder.JSONDecodeError, IndexError): section = None + section.update({ + 'affected': { + 'CVE-2021-45105': [], + 'CVE-2021-45046': [], + 'CVE-2021-44832': [], + 'CVE-2021-44228': [], + 'CVE-2021-42550': [], + 'CVE-2020-9488': [], + 'CVE-2017-5645': [], + 'CVE-2021-4104': [], + } + }) + + for file in section.get('files', []): + for report in file['reports']: + _version = report['version'] + _product = report['product'] + report['time'] = _get_ISO861_time(report['detected_at']) # 2022-01-11 20:06:41+0100, convert to ISO8601 + report.pop('detected_at') + report['fixed'] = str(report['fixed']) + report.update(_add_log4j_cves(_version, _product)) + + file_name = file['path'] + file_entry = file.get('entry') + + to_append = f'{_product}, {_version}, {file_name}' + if file_entry: + to_append += f', ({file_entry})' + + for cve in [ + 'CVE-2021-44832', + 'CVE-2021-45105', + 'CVE-2021-45046', + 'CVE-2021-44228', + 'CVE-2021-42550', + 'CVE-2020-9488', + 'CVE-2017-5645', + 'CVE-2021-4104', + ]: + if report.get(cve): + if report[cve].lower().startswith('affected') or report[cve].lower().startswith('unknown'): + section['affected'][cve].append(to_append) + + for error in section.get('errors', []): + error['time'] = _get_ISO861_time(error['created_at']) # 2022-01-11 20:06:41+0100, convert to ISO8601 + error.pop('created_at') + error['status'] = 'ERROR' + return section @@ -366,47 +546,24 @@ def inv_cve_2021_44228_log4j_report(params, section: Dict) -> InventoryResult: for report in file['reports']: key_columns = {'index': index} inventory_columns = {'path': file['path']} - status_columns = report - - timestamp = status_columns['detected_at'] # 2022-01-11 20:06:41+0100, convert to ISO8601 - status_columns['time'] = f'{timestamp[:10]}T{timestamp[11:22]}:{timestamp[22:]}' # 2022-01-11T20:06:41+01:00 - status_columns.pop('detected_at') - status_columns['fixed'] = str(status_columns['fixed']) - - if not params.get('do_status_data'): - inventory_columns.update(status_columns) - status_columns = {} + inventory_columns.update(report) yield TableRow( path=path, key_columns=key_columns, inventory_columns=inventory_columns, - status_columns=status_columns ) index += 1 if not params.get('do_not_inv_errors'): for error in section.get('errors', []): key_columns = {'index': index} - inventory_columns = {'path': error['path']} - - status_columns = error - status_columns.pop('path') - - timestamp = status_columns['created_at'] # 2022-01-11 20:06:41+0100, convert to ISO8601 - status_columns['time'] = f'{timestamp[:10]}T{timestamp[11:22]}:{timestamp[22:]}' # 2022-01-11T20:06:41+01:00 - status_columns.pop('created_at') - status_columns['status'] = 'ERROR' - - if not params.get('do_status_data'): - inventory_columns.update(status_columns) - status_columns = {} + inventory_columns = error yield TableRow( path=path, key_columns=key_columns, inventory_columns=inventory_columns, - status_columns=status_columns ) index += 1 @@ -417,6 +574,57 @@ register.inventory_plugin( inventory_ruleset_name='inventory_cve_2021_44228_log4j', inventory_default_parameters={ 'do_not_inv_errors': False, - 'do_status_data': False, }, ) + + +# ######################################################################################################### +# +# Check plugin for log4j per CVE +# +# ######################################################################################################### + + +def discovery_cve_2021_44228_log4j_cves(params, section: Dict) -> DiscoveryResult: + for cve in section['affected'].keys(): + if len(section['affected'][cve]) or params['add_empty_cves'] is True: + yield Service(item=cve) + + +def check_cve_2021_44228_log4j_cves(item, params, section: Dict) -> CheckResult: + try: + cve = section['affected'][item] + except KeyError: + yield Result(state=State.UNKNOWN, summary=f'{item} not found in agent data.') + return + + yield from check_levels( + value=len(cve), + label='Affected files', + render_func=lambda v: str(v), + levels_upper=params['files_affected'], + metric_name='files_affected', + ) + + yield Result(state=State.OK, notice=f'\nlist of file affected by {item}:') + if cve: + yield Result(state=State.OK, notice='\n'.join(cve)) + else: + yield Result(state=State.OK, notice='\n no affected files found') + + +register.check_plugin( + name='cve_2021_44228_log4_cves', + sections=['cve_2021_44228_log4j_report'], + service_name='log4j %s', + discovery_default_parameters={ + 'add_empty_cves': False, + }, + discovery_ruleset_name='discovery_cve_2021_44228_log4_cves', + discovery_function=discovery_cve_2021_44228_log4j_cves, + check_function=check_cve_2021_44228_log4j_cves, + check_default_parameters={ + 'files_affected': (1, 1), + }, + 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 9d39ff17c4a9bd4e59ff7c3ee64e88ff53af2097..a7b024f4a33e1affaddd5eb509086d830728b0b6 100755 --- a/agents/bakery/cve_2021_44228_log4j.py +++ b/agents/bakery/cve_2021_44228_log4j.py @@ -18,8 +18,8 @@ # added PLUGIN_TIMEOUT to the linux config (fix scanner got not killed on timeout by the agent) # 2022-01-05: added PLUGIN_TIMEOUT to the windows config (to match the linux variant) # 2022-01-11: added option to add json report to inventory -# 2022-01-14: reorganised append to log (--csv-log-path/--json-log-path) and -# add report to inventory options (-report-path) +# 2022-01-14: reorganised append to log (--csv-log-path/--json-log-path) and add report to inventory options (-report-path) +# 2022-01-25: added option --exclude-pattern # from pathlib import Path from typing import List @@ -27,7 +27,7 @@ from typing import List from cmk.base.cee.plugins.bakery.bakery_api.v1 import FileGenerator, OS, Plugin, PluginConfig, register -bakery_version = '20220114.v0.0.9' +bakery_version = '20220125.v0.1.0' def get_cve_2021_44228_log4j_files(conf: List[any]) -> FileGenerator: @@ -43,7 +43,6 @@ def get_cve_2021_44228_log4j_files(conf: List[any]) -> FileGenerator: attach_report_to_output = None config_path = '' search_path = '' - path_separator = '' interval = 86400 timeout = 300 @@ -57,10 +56,8 @@ def get_cve_2021_44228_log4j_files(conf: List[any]) -> FileGenerator: if conf[0] == 'linux': config_path = '/etc/check_mk/' - path_separator = '/' elif conf[0] == 'windows': config_path = 'C:\\ProgramData\\checkmk\\agent\\config\\' - path_separator = '\\' if options['search_in'] == 'all_drives': options_array.append('--all-drives') @@ -103,13 +100,6 @@ def get_cve_2021_44228_log4j_files(conf: List[any]) -> FileGenerator: if 'report_to_file' in options['reporting']: label, report_cfg = options['reporting'] report_dir = report_cfg['report_dir'].strip(' ').strip("'").strip('"') - # if report_cfg.get('log_path'): - # log_path = report_cfg['log_path'] - # if report_cfg.get('report_format') == '--report-json': - # options_array.append(f'--json-log-path "{report_dir}{path_separator}{log_path}"') - # else: - # options_array.append(f'--csv-log-path "{report_dir}{path_separator}{log_path}"') - # else: options_array.append(f'--report-dir "{report_dir}"') options_array.append(report_cfg.get('report_format', '--report-csv')) if report_cfg.get('no_empty_report'): @@ -140,14 +130,19 @@ def get_cve_2021_44228_log4j_files(conf: List[any]) -> FileGenerator: options.pop('fix_files') if options.get('exclude_paths'): - if 'exclude_paths' in options['exclude_paths']: - label, paths = options['exclude_paths'] - for path in paths: - path = path.strip(' ').strip("'").strip('"') - options_array.append(f'--exclude "{path}"') - elif 'exclude_paths_file' in options['exclude_paths']: - label, exclude_paths = options['exclude_paths'] - options_array.append(f'--exclude-config {config_path}cve_2021_44228_log4j_exclude.cfg') + if 'exclude_paths' in options['exclude_paths'].keys(): + if 'exclude_paths' in options['exclude_paths']['exclude_paths']: + label, paths = options['exclude_paths']['exclude_paths'] + for path in paths: + path = path.strip(' ').strip("'").strip('"') + options_array.append(f'--exclude "{path}"') + elif 'exclude_paths_file' in options['exclude_paths']['exclude_paths']: + label, exclude_paths = options['exclude_paths'] + options_array.append(f'--exclude-config {config_path}cve_2021_44228_log4j_exclude.cfg') + if 'exclude_paths_pattern' in options['exclude_paths'].keys(): + for path in options['exclude_paths']['exclude_paths_pattern']: + path = path.strip(' ').strip("'").strip('"') + options_array.append(f'--exclude-pattern "{path}"') options.pop('exclude_paths') if options.get('exclude_file_config'): diff --git a/cve_2021_44228_log4j.mkp b/cve_2021_44228_log4j.mkp index d2a9295b1b459166b40ef6b475ceccd59a6546e4..6e39113054c394ab7bc77adedcce0cd6aefd8ca7 100644 Binary files a/cve_2021_44228_log4j.mkp and b/cve_2021_44228_log4j.mkp differ diff --git a/doc/sample-inventory-report.png b/doc/sample-inventory-report.png new file mode 100644 index 0000000000000000000000000000000000000000..6b20bddcfbe356e99e4eec98ed34093c29f704fe Binary files /dev/null and b/doc/sample-inventory-report.png differ diff --git a/doc/sample-inventory.png b/doc/sample-inventory.png index 4f32a8a577753bd3b7dd425abb3e9d2f0ba5785b..028ead3b43bdf9ec4d3c6d3f714b439c1c73d830 100644 Binary files a/doc/sample-inventory.png and b/doc/sample-inventory.png differ diff --git a/doc/sample-log4j-services.png b/doc/sample-log4j-services.png new file mode 100644 index 0000000000000000000000000000000000000000..7d880e3b46654eb40d7a01035fd3dec7f56b3112 Binary files /dev/null and b/doc/sample-log4j-services.png differ diff --git a/doc/wato-bakery-linux.png b/doc/wato-bakery-linux.png index d7d2fc500e36ae8a19398fbc9f8703570a7e20b2..b7f6a622d3785c223287c90c8e00394f7f828d99 100644 Binary files a/doc/wato-bakery-linux.png and b/doc/wato-bakery-linux.png differ diff --git a/doc/wato-bakery-windows.png b/doc/wato-bakery-windows.png index 3b291a93540bdf790c557b2d654d68b886701dac..f977cf7b18fc47bed9dd8af3a97c160d04d8b4d1 100644 Binary files a/doc/wato-bakery-windows.png and b/doc/wato-bakery-windows.png differ diff --git a/doc/wato-inventory.png b/doc/wato-inventory.png new file mode 100644 index 0000000000000000000000000000000000000000..d56452f68ef4040a276d1a88628ff5672fa9ea40 Binary files /dev/null and b/doc/wato-inventory.png differ diff --git a/packages/cve_2021_44228_log4j b/packages/cve_2021_44228_log4j index 9cde1d445727fc2176de01c47610b4cbda44c950..f347e92d842c75fab5fc1a7eb5ea9fb14ce36a02 100644 --- a/packages/cve_2021_44228_log4j +++ b/packages/cve_2021_44228_log4j @@ -33,7 +33,7 @@ 'name': 'cve_2021_44228_log4j', 'num_files': 11, 'title': 'CVE-2021-44228-log4j scanner plugin', - 'version': '20220115.v0.0.9', + 'version': '20220125.v0.1.0', '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 48336fd39b96d6152622c0bf0d52b7f47984927b..982334d4604e4fbe0f97c39490d4c083ac62ecdf 100644 --- a/web/plugins/metrics/cve_2021_44228_log4j.py +++ b/web/plugins/metrics/cve_2021_44228_log4j.py @@ -10,7 +10,7 @@ # Metrics file for the cve_2021_44228_log4j plugin # # 2021-12-20: added run time to the perfometer -# +# 2022-01-25: added metrics/graph/perfometer for files_affected from cmk.gui.i18n import _ @@ -59,6 +59,12 @@ metric_info['run_time'] = { 'color': '33/b', } +metric_info['files_affected'] = { + 'title': _('Files affected'), + 'unit': 'count', + 'color': '13/a', +} + check_metrics['cve_2021_44228_log4j'] = { 'errors': {'auto_graph': False}, } @@ -93,6 +99,14 @@ graph_info['cve_2021_44228_log4j_runtime'] = { ], } +graph_info['cve_2021_44228_log4j_cves_files_affected'] = { + 'title': _('Files affected'), + 'metrics': [ + ('files_affected', 'area'), + ], +} + + perfometer_info.append(('stacked', [ { 'type': 'linear', @@ -112,3 +126,13 @@ perfometer_info.append(('stacked', [ 'total': 7200, }, ])) + +perfometer_info.append( + { + 'type': 'linear', + 'segments': [ + 'files_affected', + ], + 'total': 50, + }, +) diff --git a/web/plugins/views/inv_cve_2021_22448_log4j.py b/web/plugins/views/inv_cve_2021_22448_log4j.py index aaee02c3e8b38967bb95787ccd6ec6bbbea56f91..84929664ad986ff797f6c2c6c55e308ddba41fed 100644 --- a/web/plugins/views/inv_cve_2021_22448_log4j.py +++ b/web/plugins/views/inv_cve_2021_22448_log4j.py @@ -9,7 +9,9 @@ # # -# 2021-01-07: added short names +# 2022-01-07: added short names +# 2022-01-18: added additional CVEs +# 2022-01-22: added entry's for 'CVE-2021-42550' and 'CVE-2021-4104' # from cmk.gui.i18n import _ @@ -69,14 +71,22 @@ inventory_displayhints.update({ 'version', # 'hostname', 'path', - 'error', 'entry', + 'CVE-2021-45105', + 'CVE-2021-45046', + 'CVE-2021-44832', + 'CVE-2021-44228', + 'CVE-2021-42550', + 'CVE-2021-4104', + 'CVE-2020-9488', + 'CVE-2017-5645', + 'error', ], 'view': 'invcve202144228log4jreport_of_host', }, '.software.cve_2021_44228_log4j.report:*.index': {'title': _('Index'), }, '.software.cve_2021_44228_log4j.report:*.time': {'title': _('Time'), }, - '.software.cve_2021_44228_log4j.report:*.cve': {'title': _('CVE'), }, + '.software.cve_2021_44228_log4j.report:*.cve': {'title': _('CVE logpresso'), }, '.software.cve_2021_44228_log4j.report:*.status': {'title': _('Status'), }, '.software.cve_2021_44228_log4j.report:*.fixed': {'title': _('Fixed'), }, '.software.cve_2021_44228_log4j.report:*.product': {'title': _('Product'), }, @@ -85,6 +95,16 @@ inventory_displayhints.update({ '.software.cve_2021_44228_log4j.report:*.path': {'title': _('Path'), }, '.software.cve_2021_44228_log4j.report:*.entry': {'title': _('Entry'), }, '.software.cve_2021_44228_log4j.report:*.error': {'title': _('Error'), }, + + '.software.cve_2021_44228_log4j.report:*.CVE-2021-45105': {'title': _('CVE-2021-45105'), }, + '.software.cve_2021_44228_log4j.report:*.CVE-2021-45046': {'title': _('CVE-2021-45046'), }, + '.software.cve_2021_44228_log4j.report:*.CVE-2021-44832': {'title': _('CVE-2021-44832'), }, + '.software.cve_2021_44228_log4j.report:*.CVE-2021-44228': {'title': _('CVE-2021-44228'), }, + '.software.cve_2021_44228_log4j.report:*.CVE-2020-9488' : {'title': _('CVE-2020-9488'), }, + '.software.cve_2021_44228_log4j.report:*.CVE-2017-5645' : {'title': _('CVE-2017-5645'), }, + '.software.cve_2021_44228_log4j.report:*.CVE-2021-42550': {'title': _('CVE-2021-42550'), }, + '.software.cve_2021_44228_log4j.report:*.CVE-2021-4104': {'title': _('CVE-2021-4104'), }, + }) declare_invtable_view( diff --git a/web/plugins/wato/cve_2021_44228_log4j.py b/web/plugins/wato/cve_2021_44228_log4j.py index ac37be08901e507aac4d6deafe47b03caa086ddf..92062782e71e4d6e6280668004c98a58c561780a 100644 --- a/web/plugins/wato/cve_2021_44228_log4j.py +++ b/web/plugins/wato/cve_2021_44228_log4j.py @@ -15,13 +15,17 @@ # 2021-12-30: added bulk config for search path end exclude path # 2022-01-02: added options for syslog facility, rfc5424 syslog message format, append reporting to file # added exclude files (buk) -# 2022-01-05: changed display names to "CVE scanner for log4j (CVE-2021-44228-log4j)" +# 2022-01-05: changed display names to "log4j CVE scanner (CVE-2021-44228-log4j)" # 2022-01-06: made "Silent output" enabled by default # 2022-01-07: changed "Cache time" into "Scan interval!" # 2022-01-11: added option to add json report to inventory # 2022-01-14: moved append to log outside of enable reporting # removed reporting to file -# +# 2022-01-14: added options for per CVE check +# changed display name (again) from 'CVE scanner for log4j (CVE-2021-44228-log4j)' +# to 'log4j CVE scanner (CVE-2021-44228-log4j)' +# enabled 'attach_report_to_output' in "reporting" by default for new rules +# 2022-01-25: added option --exclude-pattern from cmk.gui.i18n import _ from cmk.gui.valuespec import ( @@ -45,7 +49,7 @@ from cmk.gui.valuespec import ( from cmk.gui.plugins.wato import ( rulespec_registry, RulespecGroupCheckParametersOperatingSystem, - # RulespecGroupCheckParametersDiscovery, + RulespecGroupCheckParametersDiscovery, CheckParameterRulespecWithItem, HostRulespec, ) @@ -62,7 +66,7 @@ from cmk.gui.cee.plugins.wato.agent_bakery.rulespecs.utils import ( RulespecGroupMonitoringAgentsAgentPlugins, ) -bakery_plugin_version = '20220115.v0.0.5' +bakery_plugin_version = '20220125.v0.0.7' # ######################################################################################################### # @@ -219,12 +223,67 @@ rulespec_registry.register( check_group_name='cve_2021_44228_log4j', group=RulespecGroupCheckParametersOperatingSystem, parameter_valuespec=_valuespec_cve_2021_44228_log4j, - title=lambda: _('CVE scanner for log4j (CVE-2021-44228-log4j)'), + title=lambda: _('log4j CVE scanner (CVE-2021-44228-log4j)'), match_type='dict', # item_spec=lambda: TextUnicode(title=_('Service name'), ), )) +def _valuespec_cve_2021_44228_log4_cves(): + return Dictionary( + elements=[ + ('files_affected', + Tuple( + title=_('Files affected'), + help=_('Upper levels for # of affected files found.'), + elements=[ + Integer(title=_('Warning at'), minvalue=0, unit=_('Files'), default_value=1), + Integer(title=_('Critical at'), minvalue=0, unit=_('Files'), default_value=1), + ])), + ]) + + +rulespec_registry.register( + CheckParameterRulespecWithItem( + check_group_name='cve_2021_44228_log4_cves', + group=RulespecGroupCheckParametersOperatingSystem, + parameter_valuespec=_valuespec_cve_2021_44228_log4_cves, + title=lambda: _('log4j CVEs'), + match_type='dict', + item_spec=lambda: TextUnicode(title=_('CVE'), ), + )) + + +# ######################################################################################################### +# +# Discovery rule set for the check plugin cve_2021_44228_log4j.py +# +# ######################################################################################################### + + +def _valuespec_discovery_cve_2021_44228_log4_cves(): + return Dictionary( + title=_('log4j CVEs'), + elements=[ + ('add_empty_cves', + FixedValue( + True, + title=_('add CVEs without affected files'), + totext=_('The plugin will add CVEs even if there are no affected files found.'), + )), + ], + ) + + +rulespec_registry.register( + HostRulespec( + group=RulespecGroupCheckParametersDiscovery, + match_type='dict', + name='discovery_cve_2021_44228_log4_cves', + valuespec=_valuespec_discovery_cve_2021_44228_log4_cves, + )) + + # ######################################################################################################### # # Inventory rule set for the check plugin cve_2021_44228_log4j.py @@ -233,7 +292,7 @@ rulespec_registry.register( def _valuespec_inventory_cve_2021_44228_log4j(): return Dictionary( - title=_('CVE scanner for log4j (CVE-2021-44228-log4j)'), + title=_('log4j CVE scanner (CVE-2021-44228-log4j)'), elements=[ ('do_not_inv_summary', @@ -250,16 +309,6 @@ def _valuespec_inventory_cve_2021_44228_log4j(): totext=_('errors (skipped files) will not be added to the inventory'), help=_('This will not add errors (skipped files) to the inventory if enabled.'), )), - # ('do_status_data', - # FixedValue( - # True, - # title=_('use Status data inventory'), - # totext=_('use of Status data inventory enabled'), - # help=_( - # 'This uses Status data inventory if enabled. Status data inventory needs to be enabled by a ' - # 'matching "Do hardware/software inventory" rule. This might lead to a increased resource usage' - # ), - # )), ], ) @@ -290,14 +339,17 @@ _base_options_config_fix_files = ( '--force-fix', title=_('Fix files. (Use at your own risk!)'), totext=_('Files will be fixed'), - help=_('Do not prompt confirmation. Don\'t use this option unless you know what you are doing.') + help=_( + 'Do not prompt confirmation. Don\'t use this option unless you know what you are doing. ' + 'Implements the "--force-fix" option.' + ) )), ('backup_dir', TextUnicode( title=_('Backup directory (must exist)'), help=_( - 'Specify backup file path. Remember the directory must exist ' - 'and the scanner must be able to write there!' + 'Specify backup file path. Remember the directory must exist and the scanner must be able to ' + 'write there! Implements the "--backup-path" option.' ), allow_empty=False, )), @@ -343,7 +395,7 @@ _base_options_config_scan_logback = ( '--scan-logback', title=_('Scan for logback (CVE-2021-42550)'), totext=_('Scan for logback (CVE-2021-42550) enabled'), - help=_('Enables scanning for logback CVE-2021-42550.'), + help=_('Enables scanning for logback CVE-2021-42550. Implements the "--scan-logback" option'), ) ) @@ -353,7 +405,7 @@ _base_options_config_log4j_1 = ( '--scan-log4j1', title=_('Scan for log4j 1 versions (CVE-2021-4104)'), totext=_('Scan for log4j 1 versions (CVE-2021-4104) enabled'), - help=_('Enables scanning for log4j 1 versions (CVE-2021-4104).'), + help=_('Enables scanning for log4j 1 versions (CVE-2021-4104). Implements the "--scan-log4j1" option.'), ) ) @@ -363,7 +415,9 @@ _base_options_config_scan_zip = ( '--scan-zip', title=_('Scan zip files (increase timeout)'), totext=_('Scanning .zip files enabled'), - help=_('Scan also .zip extension files. This option may slow down scanning.'), + help=_( + 'Scan also .zip extension files. This option may slow down scanning. Implements the "--scan-zip" option' + ), ) ) @@ -373,7 +427,7 @@ _base_options_config_no_symlink = ( '--no-symlink', title=_('Ignore symlinks'), totext=_('Ignore symlinks enabled'), - help=_('Do not detect symlink as vulnerable file.'), + help=_('Do not detect symlink as vulnerable file. Implements the "--no-symlink" option'), ) ) @@ -383,8 +437,10 @@ _base_options_config_silent = ( '--silent', title=_('Silent output'), totext=_('Silent output enabled'), - help=_('Do not print anything until scan is completed. This will ' - 'remove some progress messages from the scanner output'), + help=_( + 'Do not print anything until scan is completed. This will remove some progress messages from the scanner ' + 'output. Implements the "--silent" option.' + ), ) ) @@ -395,110 +451,31 @@ _base_option_config_exclude_fs = ( orientation='horizontal', allow_empty=False, valuespec=TextInput(allow_empty=False, regex='[a-zA-Z0-9\.]'), - help=_('Exclude paths by file system type. nfs, nfs3, nfs4, cifs, ' - 'tmpfs, devtmpfs, fuse.sshfs and iso9660 is ignored by default.'), + help=_( + 'Exclude paths by file system type. nfs, nfs3, nfs4, cifs, tmpfs, devtmpfs, fuse.sshfs and iso9660 is ' + 'ignored by default. Implements the "--exclude-fs" option' + ), ) ) - -_base_option_config_syslog = ( - 'syslog', - Dictionary( - title=_('Enable syslog reporting'), - elements=[ - ('syslog_server', - TextUnicode( - title=_('Syslog server'), - help=_('IP-Address or hostname of the syslog server to log to.'), - allow_empty=False, - )), - ('syslog_port', - Integer( - title=_('Syslog server Port'), - help=_('Port of the syslog server. Default ist 512.'), - default_value=514, - minvalue=1, - maxvalue=65535 - )), - ('syslog_level', - DropdownChoice( - title=_('Loglevel'), - help=_( - 'Use "alert" level for SIEM integration. It will report vulnerable/potential vulnerable files.\n' - 'Use "info" level for BI reporting. It reports also MITIGATED files. This is the default mode.\n' - 'Use "debug" level for error reporting'), - choices=[ - ('alert', _('Alert')), - ('info', _('Info')), - ('debug', _('Debug')), - ], - default_value='info', - )), - ('syslog_facility', - DropdownChoice( - title=_('Facility'), - help=_('Default value is 16 (local0). Facility value must be in the range of 0 to 23'), - choices=syslog_facilities, - - # from ~/lib/check_mk/gui/mkeventd.py - # syslog_facilities: DropdownChoices = [ - # (0, "kern"), - # (1, "user"), - # (2, "mail"), - # (3, "daemon"), - # (4, "auth"), - # (5, "syslog"), - # (6, "lpr"), - # (7, "news"), - # (8, "uucp"), - # (9, "cron"), - # (10, "authpriv"), - # (11, "ftp"), - # (12, "(12: unused)"), - # (13, "(13: unused)"), - # (14, "(14: unused)"), - # (15, "(15: unused)"), - # (16, "local0"), - # (17, "local1"), - # (18, "local2"), - # (19, "local3"), - # (20, "local4"), - # (21, "local5"), - # (22, "local6"), - # (23, "local7"), - # (31, "snmptrap"), - # ] - default_value=16, - )), - ('syslog_rfc5424', - FixedValue( - '--rfc5424', - title=_('Use RFC5424 syslog format'), - totext=_('Formatting of syslog messages as in RFC5424 enabled'), - help=_('Without formatting the message as of RFC5424, the message looks like this \"<133>{\"time\": ' - '\"2022-01-01 19:35:25+0100\", \"hostname\": \"checkmk\", \"path\": ' - '\"/usr/bin/pycharm/pycharm-community-2021.1.3/lib/log4j.jar\", \"entry\": \"\", \"product\": ' - '\"Log4j 1\", \"version\": \"1.2.17.2\", \"cve\": \"CVE-2021-4104\", \"status\": ' - '\"MITIGATED\", \"fixed\": false}\". \nThis will break some syslog implementations becaus of ' - 'the missing/wrong syslog header. For example CMKs event console will show \"{\"time\":\" as ' - 'the Application. With RFC5424 enabled the message is changed like this ' - '\"<133> 1 2022-01-01T23:20:50.52Z HOSTNAME LOPGRESSO LOG4J2-SCAN DETECT - {your message}\". ' - 'APP-NAME: LOPGRESSO, PROCID: LOG4J2-SCAN, MSGID: DETECT. MSGID can also be ERROR in case of a ' - 'scan error, for example on broken zip or jar files.' - ), - )), - ], - required_keys=['syslog_server'] - ), -) - _base_option_config_report = ( 'reporting', CascadingDropdown( title=_('Enable reporting'), - default_value='report_to_file', sorted=False, choices=[ + ('attach_report_to_output', + _('Send report to checkmk'), + FixedValue( + True, + totext=_('Send report to checkmk enabled (See inline help please!!)'), + help=_( + 'This option will write the report to log4j_report.json (Linux in /var/log, ' + 'Windows in C:\\Windows\\temp. This report will than integrated in the checkmk inventory and ' + 'enable the per CVE check plugin. The report file will be deleted before scanning and after ' + 'output of the contents for checkmk. Implements the "--report-json --report-path" option' + ), + )), ('report_to_file', _('Enable file reporting'), Dictionary( @@ -509,25 +486,19 @@ _base_option_config_report = ( help=_( 'Specify report output directory. If report file is not configured, the scanner will ' 'create on each run a new file in the format "log4j2_scan_report_yyyyMMdd_HHmmss" with ' - 'the extension "csv" or "json". Remember the scanner must be able to write there!' + 'the extension "csv" or "json". Remember the scanner must be able to write there! ' + 'Implements the "--report-dir" option.' ), allow_empty=False, )), - # ('log_path', - # TextUnicode( - # title=_('Name of the file to report to (deprecated)'), - # help=_( - # 'This option is has moved to "Append results to log file". ' - # 'Please reconfigure your rule accordingly.' - # ), - # allow_empty=False, - # )), ('report_format', DropdownChoice( title=_('Report format'), help=_( 'Generate log4j2_scan_report_yyyyMMdd_HHmmss.csv or ' - 'log4j2_scan_report_yyyyMMdd_HHmmss.json in the report directory.'), + 'log4j2_scan_report_yyyyMMdd_HHmmss.json in the report directory. Implements the ' + '"--report-csv" or "--report-json" option.' + ), choices=[ ('--report-csv', _('CSV')), ('--report-json', _('JSON')), @@ -539,22 +510,11 @@ _base_option_config_report = ( '--no-empty-report', title=_('Don\'t create empty reports'), totext=_('Don\'t create empty reports'), - help=_('Do not generate empty report.'), + help=_('Do not generate empty report. Implements the "--no-empty-report" option.'), )), ], required_keys=['report_dir'] )), - ('attach_report_to_output', - _('Add report to checkmk inventory'), - FixedValue( - True, - totext=_('Add report to inventory enabled (See inline help please!!)'), - help=_( - 'This option will write the report to log4j_report.json (Linux in /var/log, ' - 'Windows in C:\\Windows\\temp. This report will than integrated in the checkmk inventory. ' - 'The report file will be deleted before scanning and after output of the contents for checkmk.' - ), - )), ], ), ) @@ -574,7 +534,10 @@ _base_option_append_to_log = ( ('report_format', DropdownChoice( title=_('Log file format'), - help=_('Format of the log file. Default is CSV'), + help=_( + 'Format of the log file. Default is CSV. Implements the "--csv-log-path" or "--json-log-path" ' + 'option' + ), choices=[ ('--csv-log-path', _('CSV')), ('--json-log-path', _('JSON')), @@ -593,7 +556,7 @@ _base_options_config_debug = ( '--debug', title=_('Debug scanner'), totext=_('Debug scanner enabled'), - help=_('Print exception stacktrace for debugging.'), + help=_('Print exception stacktrace for debugging. Implements the "--debug" option.'), ) ) @@ -603,39 +566,161 @@ _base_options_config_trace = ( '--trace', title=_('Trace scanner (Use only for troubleshooting!! It produces a lot ou output'), totext=_('Trace scanner enabled'), - help=_('Print all directories and files while scanning.'), + help=_('Print all directories and files while scanning. Implements the "--trace" option.'), ) ) +_base_option_config_syslog = ( + 'syslog', + Dictionary( + title=_('Enable syslog reporting'), + elements=[ + ('syslog_server', + TextUnicode( + title=_('Syslog server'), + help=_('IP-Address or hostname of the syslog server to log to. Implements the "--syslog-udp" option.'), + allow_empty=False, + )), + ('syslog_port', + Integer( + title=_('Syslog server Port'), + help=_('Port of the syslog server. Default ist 512.'), + default_value=514, + minvalue=1, + maxvalue=65535 + )), + ('syslog_level', + DropdownChoice( + title=_('Loglevel'), + help=_( + 'Use "alert" level for SIEM integration. It will report vulnerable/potential vulnerable files.\n' + 'Use "info" level for BI reporting. It reports also MITIGATED files. This is the default mode.\n' + 'Use "debug" level for error reporting. Implements the "--syslog-level" option.' + ), + choices=[ + ('alert', _('Alert')), + ('info', _('Info')), + ('debug', _('Debug')), + ], + default_value='info', + )), + ('syslog_facility', + DropdownChoice( + title=_('Facility'), + help=_( + 'Default value is 16 (local0). Facility value must be in the range of 0 to 23. Implements the ' + '"--syslog-facility" option.' + ), + choices=syslog_facilities, + + # from ~/lib/check_mk/gui/mkeventd.py + # syslog_facilities: DropdownChoices = [ + # (0, "kern"), + # (1, "user"), + # (2, "mail"), + # (3, "daemon"), + # (4, "auth"), + # (5, "syslog"), + # (6, "lpr"), + # (7, "news"), + # (8, "uucp"), + # (9, "cron"), + # (10, "authpriv"), + # (11, "ftp"), + # (12, "(12: unused)"), + # (13, "(13: unused)"), + # (14, "(14: unused)"), + # (15, "(15: unused)"), + # (16, "local0"), + # (17, "local1"), + # (18, "local2"), + # (19, "local3"), + # (20, "local4"), + # (21, "local5"), + # (22, "local6"), + # (23, "local7"), + # (31, "snmptrap"), + # ] + default_value=16, + )), + ('syslog_rfc5424', + FixedValue( + '--rfc5424', + title=_('Use RFC5424 syslog format'), + totext=_('Formatting of syslog messages as in RFC5424 enabled'), + help=_('Without formatting the message as of RFC5424, the message looks like this \"<133>{\"time\": ' + '\"2022-01-01 19:35:25+0100\", \"hostname\": \"checkmk\", \"path\": ' + '\"/usr/bin/pycharm/pycharm-community-2021.1.3/lib/log4j.jar\", \"entry\": \"\", \"product\": ' + '\"Log4j 1\", \"version\": \"1.2.17.2\", \"cve\": \"CVE-2021-4104\", \"status\": ' + '\"MITIGATED\", \"fixed\": false}\". \nThis will break some syslog implementations because of ' + 'the missing/wrong syslog header. For example CMKs event console will show \"{\"time\":\" as ' + 'the Application. With RFC5424 enabled the message is changed like this ' + '\"<133> 1 2022-01-01T23:20:50.52Z HOSTNAME LOPGRESSO LOG4J2-SCAN DETECT - {your message}\". ' + 'APP-NAME: LOPGRESSO, PROCID: LOG4J2-SCAN, MSGID: DETECT. MSGID can also be ERROR in case of a ' + 'scan error, for example on broken zip or jar files. Implements the "--rfc5424" option.' + ), + )), + ], + required_keys=['syslog_server'], + default_keys=['syslog_rfc5424'] + ), +) + _base_option_config_exclude_paths = ( 'exclude_paths', - CascadingDropdown( + Dictionary( title=_('Exclude paths'), - default_value='exclude_paths', - sorted=False, - choices=[ + elements=[ ('exclude_paths', - _('Exclude paths'), + # _('Exclude paths'), + CascadingDropdown( + title=_('Exclude paths'), + default_value='exclude_paths', + sorted=False, + choices=[ + ('exclude_paths', + _('Exclude paths'), + ListOfStrings( + orientation='horizontal', + allow_empty=False, + valuespec=TextInput(allow_empty=False, regex='[^|<>&]'), + help=_( + 'Implements --exclude [path_prefix] Path prefixes of directories whose absolute path ' + 'starts with the specified value will be excluded. Does not support relative paths. ' + 'You can specify multiple --exclude [path_prefix] pairs' + ), + )), + ('exclude_paths_file', + _('Exclude paths (bulk)'), + TextAreaUnicode( + help=_( + 'Implements --exclude-config [config_file_path] Specify exclude path prefix list in ' + 'text file. Paths should be separated by new line. Prepend # for comment.' + ), + allow_empty=False, + forbidden_chars='|<>&', + strip=True, + cols=85, + rows=5, + default_value='# Specify path list. Paths should be separated by new line. Prepend # for comment.\n' + )) + ], + ) + ), + ('exclude_paths_pattern', ListOfStrings( + title=_('Exclude paths by pattern'), orientation='horizontal', allow_empty=False, valuespec=TextInput(allow_empty=False, regex='[^|<>&]'), - help=_('Exclude specified paths from the scanning'), + help=_( + 'Implements --exclude-pattern [pattern] Exclude specified paths of directories by pattern. ' + 'Supports fragments. You can specify multiple --exclude-pattern [pattern] pairs (non regex)' + ), )), - ('exclude_paths_file', - _('Exclude paths (bulk)'), - TextAreaUnicode( - help='Specify path list. Paths should be separated by new line. Prepend # for comment.', - allow_empty=False, - forbidden_chars='|<>&', - strip=True, - cols=85, - rows=5, - default_value='# Specify path list. Paths should be separated by new line. Prepend # for comment.\n' - )) ], - ) + ), ) @@ -643,7 +728,10 @@ _base_option_config_exclude_files = ( ('exclude_file_config', TextAreaUnicode( title=_('Exclude files (bulk)'), - help='Specify file list. Files should be separated by new line. Prepend # for comment.', + help=_( + 'Specify file list. Files should be separated by new line. Prepend # for comment. Implements the ' + '"--exclude-file-config " option.' + ), allow_empty=False, forbidden_chars='|<>&', strip=True, @@ -656,7 +744,7 @@ _base_option_config_exclude_files = ( def _valuespec_agent_config_cve_2021_44228_log4j(): return CascadingDropdown( - title=_('CVE scanner for log4j (CVE-2021-44228-log4j)'), + title=_('log4j CVE scanner (CVE-2021-44228-log4j)'), help=_( f'If you activate this option, then the agent plugin <tt>cve_2021_44228_log4j</tt> will be deployed. ' f'This will scan for files with the CVE-2021-44228-log4j issue. (Plugin version: {bakery_plugin_version})' @@ -685,7 +773,10 @@ def _valuespec_agent_config_cve_2021_44228_log4j(): ('include_paths_file', _('Search paths (bulk)'), TextAreaUnicode( - help='Specify path list. Paths should be separated by new line. Prepend # for comment.', + help=_( + 'Specify path list. Paths should be separated by new line. Prepend # for comment. ' + 'Implements the "-f" option.' + ), allow_empty=False, forbidden_chars='|<>&:', strip=True, @@ -715,7 +806,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=['silent'], + default_keys=['silent', 'reporting'], )), ('windows', _('Deploy Windows CVE-2021-44228-log4j agent plugin'), @@ -733,7 +824,10 @@ def _valuespec_agent_config_cve_2021_44228_log4j(): orientation='horizontal', allow_empty=False, valuespec=TextInput(size=1, maxlen=1, minlen=1, allow_empty=False, regex='[a-zA-Z]'), - help=_('This drives will be scanned, default is "--all-drives"'), + help=_( + 'This drives will be scanned, default is "--all-drives". Implements the ' + '"--drives" option' + ), default_value=['C'], )), ('search_paths', @@ -748,7 +842,10 @@ def _valuespec_agent_config_cve_2021_44228_log4j(): ('include_paths_file', _('Search paths (bulk)'), TextAreaUnicode( - help='Specify path list. Paths should be separated by new line. Prepend # for comment.', + help=_( + 'Specify path list. Paths should be separated by new line. Prepend # for comment. ' + 'Implements the "-f" option.' + ), allow_empty=False, forbidden_chars='|<>&', strip=True, @@ -778,7 +875,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=['silent'], + default_keys=['silent', 'reporting'], )), (None, _('Do not deploy the CVE-2021-44228-log4j agent plugin')), ],