File: //usr/local/lib/python3.9/site-packages/wordfence/cli/malwarescan/definition.py
from wordfence.util.pcre import PCRE_DEFAULT_MATCH_LIMIT, \
PCRE_DEFAULT_MATCH_LIMIT_RECURSION
from wordfence.util.units import byte_length
from ...scanning.matching import MatchEngine
from ..subcommands import SubcommandDefinition, UsageExample
from ..config.typing import ConfigDefinitions
from .reporting import SCAN_REPORT_CONFIG_OPTIONS
config_definitions: ConfigDefinitions = {
"read-stdin": {
"description": "Read paths from stdin. If not specified, paths will "
"automatically be read from stdin when input is not "
"from a TTY.",
"context": "ALL",
"argument_type": "OPTIONAL_FLAG",
"default": None
},
"file-list-separator": {
"short_name": "s",
"description": "Separator used when listing files via stdin. Defaults "
"to the null byte.",
"context": "ALL",
"argument_type": "OPTION",
"default": "AA==",
"default_type": "base64"
},
**SCAN_REPORT_CONFIG_OPTIONS,
"exclude-signatures": {
"short_name": "e",
"description": "Specify rule IDs to exclude from the scan. Can be "
"comma-delimited and/or specified multiple times.",
"context": "ALL",
"argument_type": "OPTION_REPEATABLE",
"default": None,
"meta": {
"separator": ",",
"value_type": int
}
},
"include-signatures": {
"short_name": "i",
"description": "Specify rule IDs to include in the scan. Can be "
"comma-delimited and/or specified multiple times.",
"context": "ALL",
"argument_type": "OPTION_REPEATABLE",
"default": None,
"meta": {
"separator": ",",
"value_type": int
}
},
"images": {
"description": "Include image files in the scan.",
"context": "ALL",
"argument_type": "FLAG",
"default": False
},
"include-all-files": {
"short_name": "a",
"description": "Scan all files. By default, only files matching "
"certain extensions are scanned",
"context": "ALL",
"argument_type": "FLAG",
"default": False
},
"include-files": {
"short_name": "n",
"description": "Only scan filenames that are exact matches. Can be "
"used multiple times.",
"context": "ALL",
"argument_type": "OPTION_REPEATABLE",
"default": None,
"meta": {
"separator": ",",
"accepts_file": True
}
},
"exclude-files": {
"short_name": "x",
"description": "Do not scan filenames that are exact matches. Can be "
"used multiple times. Denials take precedence over "
"allows.",
"context": "ALL",
"argument_type": "OPTION_REPEATABLE",
"default": None,
"meta": {
"separator": ",",
"accepts_file": True
}
},
"include-files-pattern": {
"short_name": "N",
"description": "Python regex allow pattern. Only matching filenames "
"will be scanned.",
"context": "ALL",
"argument_type": "OPTION_REPEATABLE",
"default": None,
"meta": {
"separator": ","
}
},
"exclude-files-pattern": {
"short_name": "X",
"description": "Python regex deny pattern. Matching filenames will "
"not be scanned.",
"context": "ALL",
"argument_type": "OPTION_REPEATABLE",
"default": None,
"meta": {
"separator": ","
}
},
"allow-io-errors": {
"description": "Allow scanning to continue if IO errors are "
"encountered. Files that cannot be read will "
"be skipped and a warning will be logged. This is "
"the default behavior.",
"context": "ALL",
"argument_type": "FLAG",
"default": True
},
"chunk-size": {
"short_name": "z",
"description": "Size of file chunks that will be scanned. Use a whole "
"number followed by one of the following suffixes: b "
"(byte), k (kibibyte), m (mebibyte). Defaults to 3m.",
"context": "ALL",
"argument_type": "OPTION",
"default": 3145728,
"meta": {
"value_type": byte_length
}
},
"scanned-content-limit": {
"short_name": "M",
"description": "The maximum amount of data to scan in each file."
" Content beyond this limit will not be scanned."
" Defaults to 50 mebibytes. Use a whole number followed"
" by one of the following suffixes: b (byte),"
" k (kibibyte), m (mebibyte).",
"context": "ALL",
"argument_type": "OPTION",
"default": byte_length('50m'),
"meta": {
"value_type": byte_length
}
},
"match-engine": {
"description": "The regex engine to use for malware scanning.",
"context": "ALL",
"argument_type": "OPTION",
"default": MatchEngine.get_default_option(),
"meta": {
"valid_options": MatchEngine.get_options()
}
},
"match-all": {
"description": "If set, all possible signatures will be checked "
"against each scanned file. Otherwise, only the "
"first matching signature will be reported",
"context": "ALL",
"argument_type": "FLAG",
"default": False
},
"pcre-backtrack-limit": {
"description": "The regex backtracking limit for signature evaluation",
"context": "ALL",
"argument_type": "OPTION",
"default": PCRE_DEFAULT_MATCH_LIMIT,
"meta": {
"value_type": int
}
},
"pcre-recursion-limit": {
"description": "The regex recursion limit for signature evaluation",
"context": "ALL",
"argument_type": "OPTION",
"default": PCRE_DEFAULT_MATCH_LIMIT_RECURSION,
"meta": {
"value_type": int
}
},
"workers": {
"short_name": "w",
"description": "Number of worker processes used to perform scanning. "
"Defaults to 1 worker process.",
"context": "ALL",
"argument_type": "OPTION",
"default": 1
},
"progress": {
"description": "Display scan progress in the terminal with a curses "
"interface",
"context": "CLI",
"argument_type": "FLAG",
"default": False
},
"pre-compile": {
"description": "Pre-compile and cache the signature set without "
"actually running a scan",
"context": "CLI",
"argument_type": "FLAG",
"default": False,
"category": "Signature Compilation"
},
"pre-compile-generic": {
"description": "Pre-compile and cache the signature set without "
"any CPU-specific optimizations and without running "
"a scan",
"context": "CLI",
"argument_type": "FLAG",
"default": False,
"category": "Signature Compilation"
},
"pattern-database-path": {
"description": "Use an alternate path for storage of the pattern "
"database",
"context": "ALL",
"argument_type": "OPTION",
"meta": {
"accepts_file": True
},
"default": None,
"category": "Signature Compilation"
},
"compile-local": {
"description": "Always compile the signature set locally rather than "
"attempting to download a pre-compiled set",
"context": "ALL",
"argument_type": "FLAG",
"default": False,
"category": "Signature Compilation"
},
"re-compile": {
"description": "Always re-compile the signature set rather than using "
"a cached version (when compiling locally)",
"context": "CLI",
"argument_type": "FLAG",
"default": False,
"category": "Signature Compilation"
},
"profile": {
"description": "Profile scan performance",
"context": "CLI",
"argument_type": "FLAG",
"default": False,
"hidden": True
},
"profile-path": {
"description": "Path at which to save profiling results",
"context": "CLI",
"argument_type": "OPTION",
"default": None,
"hidden": True
},
"direct-io": {
"short_name": "D",
"description": "Use direct IO when opening files to avoid caching",
"context": "ALL",
"argument_type": "FLAG",
"default": False
}
}
cacheable_types = {
'wordfence.intel.signatures.SignatureSet',
'wordfence.intel.signatures.CommonString',
'wordfence.intel.signatures.Signature',
'wordfence.intel.signatures.PrecompiledSignatureSet',
'wordfence.api.licensing.License'
}
examples = [
UsageExample(
'Scan /var/www/html for malicious files and display real-time output',
'wordfence malware-scan --progress /var/www/html'
),
UsageExample(
'Scan for malicious files in multiple directories and record the '
'results to a CSV file',
'wordfence malware-scan --output-path /home/user/wordfence-cli.csv '
'/home/user-one/dir /home/user-two/dir /home/user-three/dir'
),
UsageExample(
'Scan a directory for malicious files with any extension using 4 '
'worker processes, writing each matching file name to a line in '
'results.txt',
'wordfence malware-scan -a -w 4 --output-path /path/to/results.txt '
'--output-format line-delimited /path/to/scan'
),
UsageExample(
'Scan only files with a .js extension for malware',
'wordfence malware-scan --include-files-pattern ".*\\.js$" '
'/path/to/scan'
),
UsageExample(
'Find files updated in the last 60 and scan them for malware',
'find /var/www/ -cmin -60 -type f -print0 | wordfence malware-scan '
'--output-path /home/username/wordfence-cli.csv'
)
]
definition = SubcommandDefinition(
name='malware-scan',
usage='[OPTIONS] [PATH]...',
description='Scan files for malware',
config_definitions=config_definitions,
config_section='MALWARE_SCAN',
cacheable_types=cacheable_types,
previous_names={'scan'},
examples=examples,
uses_license=True,
accepts_directories=True,
accepts_files=True
)