def has_no_password_protection(path: str) -> bool: """ Check if .jks files are password protected. :param path: path to check """ if not os.path.exists(path): show_unknown('Path does not exist', details=dict(path=path)) return False jks_with_password: list = [] jks_without_password: list = [] for full_path in full_paths_in_dir(path): if not full_path.endswith('.jks'): continue try: jks.KeyStore.load(full_path, '') except jks.util.KeystoreSignatureException: # has password jks_with_password.append(dict(path=full_path, sha256=get_sha256(full_path))) else: # has not password jks_without_password.append(dict(path=full_path, sha256=get_sha256(full_path))) if jks_without_password: show_open('JKS is/are not password protected', details=dict(jks_without_password=jks_without_password)) return True show_close('JKS is/are password protected', details=dict(jks_with_password=jks_with_password)) return False
def _get_requirements_pom_xml(path: str) -> list: """ Get list of requirements from Maven project. Files supported are pom.xml :param path: Project path """ reqs = [] namespaces = {'xmlns': 'http://maven.apache.org/POM/4.0.0'} for full_path in full_paths_in_dir(path): if not full_path.endswith('pom.xml'): continue tree = parse(full_path) root = tree.getroot() deps = root.findall(".//xmlns:dependency", namespaces=namespaces) for dep in deps: artifact_id = dep.find("xmlns:artifactId", namespaces=namespaces) version = dep.find("xmlns:version", namespaces=namespaces) if version is not None: if version.text.startswith('$'): reqs.append((full_path, artifact_id.text, None)) else: reqs.append((full_path, artifact_id.text, version.text)) else: reqs.append((full_path, artifact_id.text, None)) return reqs
def _get_requirements(path: str) -> list: """ Get list of requirements from NuGet project. Files supported are packages.config :param path: Project path """ reqs = [] for full_path in full_paths_in_dir(path): if not full_path.endswith('packages.config'): continue tree = parse(full_path) deps = tree.findall(".//package") reqs += [(dep.attrib['id'], dep.attrib['version']) for dep in deps] return reqs
def _use_passwords(path: str, passwords: list) -> bool: """ Check if a JKS file has been protected by any of ``passwords``. :param path: path to check :param passwords: passwords to test """ if not os.path.exists(path): show_unknown('Path does not exist', details=dict(path=path)) return False opened_jks: list = [] closed_jks: list = [] passwords = ['', *(p for p in set(passwords))] for full_path in full_paths_in_dir(path): if not full_path.endswith('.jks'): continue success: bool = False for password in passwords: try: jks.KeyStore.load(full_path, password) except jks.util.KeystoreSignatureException: # wrong password continue else: # correct password success = True break if success: opened_jks.append(dict(path=full_path, password=password, sha256=get_sha256(full_path))) else: closed_jks.append(dict(path=full_path, sha256=get_sha256(full_path))) if opened_jks: show_open('JKS is/are protected by a password from the list', details=dict(opened_jks=opened_jks, tested_passwords=passwords)) return True show_close('JKS is/are protected by a password from the list', details=dict(closed_jks=closed_jks, tested_passwords=passwords)) return False
def _insecure_functions_in_dir(py_dest: str, exclude: list = None) -> bool: """ Search for insecure functions in dir. :param py_dest: Path to a Python script or package. :param exclude: Paths that contains any string from this list are ignored. """ if not exclude: exclude = [] res = [ _insecure_functions_in_file(full_path) for full_path in full_paths_in_dir(py_dest) if full_path.endswith(LANGUAGE_SPECS['extensions']) and not any( x in full_path for x in exclude) ] return list(filter(None, res))
def _get_requirements_build_gradle(path: str) -> list: """ Get list of requirements from Maven project. Files supported are build.gradle :param path: Project path """ reqs = [] for file_path in full_paths_in_dir(path): if not file_path.endswith('build.gradle'): continue with open(file_path, encoding='latin-1') as file_fd: file_content = file_fd.read() string = MatchFirst([quotedString('"'), quotedString("'")]) string.setParseAction(lambda x: [x[0][1:-1]]) grammars: list = [ Suppress(Keyword('compile') + Optional('(')) + string.copy()('package'), Suppress(Keyword('compile') + Optional('(')) + Suppress(Keyword('group') + ':') + string.copy()('group') + Suppress(',') + Suppress(Keyword('name') + ':') + string.copy()('name') + Suppress(',') + Suppress(Keyword('version') + ':') + string.copy()('version'), ] for grammar in grammars: for tokens, _, _ in grammar.scanString(file_content): matches = tokens.asDict() if 'package' in matches: if ':' in matches['package']: name, version = matches['package'].rsplit(':', 1) else: name, version = matches['package'], None reqs.append((file_path, name, version)) else: reqs.append( (file_path, f"{matches['group']}:{matches['name']}", matches['version'])) reqs.append( (file_path, matches['group'], matches['version'])) return reqs
def path_contains_grammar(grammar: ParserElement, path: str, lang_spec: dict, exclude: list = None) -> List[str]: """ Return a dict mapping all files in path to the line with grammar matches. :param grammar: Grammar to be searched for in path. :param path: Path to the destination file. :param lang_spec: Contains language-specific syntax elements, such as acceptable file extensions and comment delimiters. """ vulns = {} exclude = exclude if exclude else tuple() extensions = lang_spec.get('extensions') for full_path in full_paths_in_dir(path): if _path_match_extension(full_path, extensions) and \ not any(x in full_path for x in exclude): vulns.update(_path_contains_grammar(grammar, full_path)) return vulns
def _check_grammar_in_dir(grammar: ParserElement, code_dest: str, lang_spec: dict, exclude: list = None) -> Dict[str, List[str]]: """ Check grammar in directory. :param grammar: Pyparsing grammar against which file will be checked. :param code_dest: File or directory to check. :param lang_spec: Contains language-specific syntax elements, such as acceptable file extensions and comment delimiters. :param exclude: Exclude files or directories with given strings :return: Maps files to their found vulnerabilites. """ if not exclude: exclude = [] vulns = {} for full_path in full_paths_in_dir(code_dest): if not any(x in full_path for x in exclude): vulns.update(_check_grammar_in_file(grammar, full_path, lang_spec)) return vulns
def _get_requirements(path: str) -> set: """ Get a list of requirements from NPM project. Files supported are package.json and package-lock.json :param path: Project path """ reqs = set() if not os.path.exists(path): return reqs dictionary = {ord(c): None for c in '^~<=>'} for path in full_paths_in_dir(path): is_package = path.endswith('package.json') is_package_lock = path.endswith('package-lock.json') if is_package or is_package_lock: with open(path) as file: data = json.load(file) reqs.update((path, dep, ver.translate(dictionary)) for dep, ver in _get_all_versions(data)) return reqs