コード例 #1
0
ファイル: jks.py プロジェクト: jvasque6/asserts
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
コード例 #2
0
def file_does_not_exist(code_file: str) -> bool:
    """
    Check if the given file does'nt exist.

    :param code_file: Path to the file to be tested.
    """
    if os.path.exists(code_file):
        show_close('File exists',
                   details=dict(path=code_file,
                                fingerprint=get_sha256(code_file)))
        return False
    show_open('File does not exist',
              details=dict(path=code_file, fingerprint=get_sha256(code_file)))
    return True
コード例 #3
0
ファイル: lang.py プロジェクト: jvasque6/asserts
def _check_grammar_in_file_re(grammar: str, code_dest: str,
                              lang_spec: dict) -> Dict[str, List[str]]:
    """
    Check grammar in file.

    :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.
    """
    vulns = {}
    lines = []
    lang_extensions = lang_spec.get('extensions')

    if lang_extensions:
        if _path_match_extension(code_dest, lang_extensions):
            lines = _get_match_lines_re(grammar, code_dest, lang_spec)
    else:
        lines = _get_match_lines_re(grammar, code_dest, lang_spec)
    if lines:
        vulns[code_dest] = {
            'lines': str(lines)[1:-1],
            'sha256': get_sha256(code_dest),
        }
    return vulns
コード例 #4
0
ファイル: lang.py プロジェクト: jvasque6/asserts
def _path_contains_grammar(grammar: ParserElement, path: str) -> dict:
    """
    Return a dict mapping the path to the lines where the grammar matched.

    :param grammar: Grammar to be searched for in path.
    :param path: Path to the destination file.
    """
    with open(path, encoding='latin-1') as file_d:
        lines = file_d.read().splitlines()

    lines_length = tuple(map(lambda x: len(x) + 1, lines))
    file_as_string = '\n'.join(lines)

    # Given scanString expands tabs to 'n' number of spaces
    # And we count tabs as '1' char width
    # And scanString reports the match column relative to the expanded version
    # When a file contains tabs
    # Then the line numbers will get an offset
    # Given we force to parse without expanding tabs
    grammar.parseWithTabs()
    # Then the line numbers are reported correctly

    matched_lines = [
        _get_line_number(start, lines_length)
        for _, start, _ in grammar.scanString(file_as_string)
    ]

    if matched_lines:
        return {
            path: {
                'lines': str(matched_lines)[1:-1],
                'sha256': get_sha256(path),
            }
        }
    return {}
コード例 #5
0
ファイル: jks.py プロジェクト: jvasque6/asserts
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
コード例 #6
0
def has_if_without_else(java_dest: str, exclude: list = None) -> bool:
    r"""
    Check if all ``if``\ s have an ``else`` clause.

    See `REQ.161 <https://fluidattacks.com/web/rules/161/>`_.

    :param java_dest: Path to a Java source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    args = nestedExpr(opener='(', closer=')')

    if_ = Keyword('if') + args
    if_line = Optional('}') + if_ + Optional('{')

    try:
        conds = lang.check_grammar(if_line, java_dest, LANGUAGE_SPECS, exclude)
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=java_dest))
        return False
    else:
        if not conds:
            show_close('Code does not use "if" statements',
                       details=dict(code_dest=java_dest))
            return False

    block = nestedExpr(opener='{', closer='}')

    if_block = if_ + block
    else_if_block = Keyword('else') + Keyword('if') + args + block
    else_block = Keyword('else') + block

    cond_block = \
        Suppress(if_block + ZeroOrMore(else_if_block)) + Optional(else_block)
    cond_block.ignore(javaStyleComment)
    cond_block.ignore(L_CHAR)
    cond_block.ignore(L_STRING)

    vulns = {}
    for code_file, val in conds.items():
        vulns.update(lang.block_contains_empty_grammar(cond_block,
                                                       code_file, val['lines'],
                                                       _get_block))
    if not vulns:
        show_close('Code has "if" with "else" clause',
                   details=dict(file=java_dest,
                                fingerprint=get_sha256(java_dest)))
    else:
        show_open('Code has "if" without "else" clause',
                  details=dict(matched=vulns,
                               total_vulns=len(vulns)))
        return True
    return False
コード例 #7
0
ファイル: csharp.py プロジェクト: jvasque6/asserts
def has_switch_without_default(csharp_dest: str, exclude: list = None) -> bool:
    r"""
    Check if all ``switch``\ es have a ``default`` clause.

    See `REQ.161 <https://fluidattacks.com/web/rules/161/>`_.

    See `CWE-478 <https://cwe.mitre.org/data/definitions/478.html>`_.

    :param csharp_dest: Path to a C# source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    switch = Keyword('switch') + nestedExpr(opener='(', closer=')')
    switch_line = Optional('}') + switch + Optional('{')

    result = False
    try:
        switches = lang.check_grammar(switch_line, csharp_dest, LANGUAGE_SPECS,
                                      exclude)
    except FileNotFoundError:
        show_unknown('File does not exist',
                     details=dict(code_dest=csharp_dest))
        return False
    else:
        if not switches:
            show_close('Code does not have switches',
                       details=dict(code_dest=csharp_dest))
            return False

    switch_block = Suppress(switch) + nestedExpr(opener='{', closer='}')
    switch_block.ignore(javaStyleComment)
    switch_block.ignore(L_CHAR)
    switch_block.ignore(L_STRING)

    vulns = {}
    for code_file, val in switches.items():
        vulns.update(
            lang.block_contains_grammar(switch_block,
                                        code_file,
                                        val['lines'],
                                        _get_block,
                                        should_not_have=r'(?:default\s*:)'))
    if not vulns:
        show_close('Code has "switch" with "default" clause',
                   details=dict(file=csharp_dest,
                                fingerprint=get_sha256(csharp_dest)))
    else:
        show_open('Code does not have "switch" with "default" clause',
                  details=dict(matched=vulns, total_vulns=len(vulns)))
        result = True
    return result
コード例 #8
0
ファイル: lang.py プロジェクト: jvasque6/asserts
def block_contains_grammar(grammar: ParserElement,
                           code_dest: str,
                           lines: List[str],
                           get_block_fn: Callable,
                           should_have: str = '',
                           should_not_have: str = '',
                           search_for_empty: bool = False) -> List[str]:
    """
    Check block grammar.

    :param grammar: Pyparsing grammar against which file will be checked.
    :param code_dest: Source code file to check.
    :param lines: List of starting lines.
    :param get_block_fn: Function that gives block code starting at line.
    :param should_have: A string to search for in the match results.
    :param should_not_have: A string to search for in the match results.
    """
    vulns = {}
    vuln_lines = []
    if should_have:
        should_have_re = re.compile(should_have, flags=re.M)
    if should_not_have:
        should_not_have_re = re.compile(should_not_have, flags=re.M)
    with open(code_dest, encoding='latin-1') as code_f:
        file_lines = code_f.read().splitlines()
    for line in map(int, lines.split(',')):
        txt = get_block_fn(file_lines, line)
        results = grammar.searchString(txt, maxMatches=1)
        results_str = str(results)

        is_vulnerable = not search_for_empty
        if _is_empty_result(results):
            is_vulnerable = search_for_empty
        elif should_have and should_have_re.search(results_str):
            is_vulnerable = search_for_empty
        elif should_not_have and should_not_have_re.search(results_str):
            is_vulnerable = search_for_empty

        if is_vulnerable:
            vuln_lines.append(line)

    if vuln_lines:
        vulns = {
            code_dest: {
                'lines': str(vuln_lines)[1:-1],
                'sha256': get_sha256(code_dest),
            }
        }
    return vulns
コード例 #9
0
def has_ssl_disabled(apphostconf_dest: str, exclude: list = None) -> bool:
    """
    Check if SSL is disabled in ``ApplicationHost.config``.

    Search for access tag in security section in an ``ApplicationHost.config``
    source file or package.

    :param apphostconf_dest: Path to an ``ApplicationHost.config``
                             source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    tk_tag_s, _ = makeXMLTags('security')
    tk_access, _ = makeXMLTags('access')
    tag_no_comm = tk_access.ignore(htmlComment)
    tk_access_none = copy(tag_no_comm)
    tk_access_none.setParseAction(withAttribute(sslFlags='None'))
    result = False
    try:
        sec_tag = lang.check_grammar(tk_tag_s, apphostconf_dest,
                                     LANGUAGE_SPECS, exclude)
        if not sec_tag:
            show_unknown('Not files matched',
                         details=dict(code_dest=apphostconf_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist',
                     details=dict(code_dest=apphostconf_dest))
        return False
    access_tags = {}
    none_sslflags = {}
    for code_file, val in sec_tag.items():
        access_tags.update(
            lang.block_contains_grammar(tk_access, code_file, val['lines'],
                                        _get_block))

        none_sslflags.update(
            lang.block_contains_grammar(tk_access_none, code_file,
                                        val['lines'], _get_block))
    if not access_tags or none_sslflags:
        show_open('SSL is disabled',
                  details=dict(
                      matched=access_tags if access_tags else none_sslflags))
        result = True
    else:
        show_close('SSL is enabled',
                   details=dict(file=apphostconf_dest,
                                fingerprint=get_sha256(apphostconf_dest)))
    return result
コード例 #10
0
ファイル: python.py プロジェクト: jvasque6/asserts
def swallows_exceptions(py_dest: str, exclude: list = None) -> bool:
    """
    Search for swallowed exceptions.

    Identifies ``except`` blocks that are either empty
    or only contain comments or the ``pass`` statement.

    :param py_dest: Path to a Python script or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    tk_except = CaselessKeyword('except')
    tk_word = Word(alphas) + Optional('.')
    tk_pass = Literal('pass')
    tk_exc_obj = tk_word + Optional(Literal('as') + tk_word)
    parser_exception = tk_except + \
        Optional('(') + \
        Optional(delimitedList(tk_exc_obj)) + \
        Optional(')') + Literal(':')
    empty_exception = (Suppress(parser_exception) +
                       tk_pass).ignore(pythonStyleComment)

    result = False
    try:
        matches = lang.check_grammar(parser_exception, py_dest, LANGUAGE_SPECS,
                                     exclude)
        if not matches:
            show_close('Code does not have excepts',
                       details=dict(code_dest=py_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=py_dest))
        return False
    vulns = {}
    for code_file, val in matches.items():
        vulns.update(
            lang.block_contains_grammar(empty_exception, code_file,
                                        val['lines'], _get_block))
    if not vulns:
        show_close('Code does not have empty "catches"',
                   details=dict(file=py_dest, fingerprint=get_sha256(py_dest)))
    else:
        show_open('Code has empty "catches"',
                  details=dict(matched=vulns, total_vulns=len(vulns)))
        result = True
    return result
コード例 #11
0
def is_header_x_powered_by_present(webconf_dest: str,
                                   exclude: list = None) -> bool:
    """
    Search for X-Powered-By headers in a Web.config source file or package.

    :param webconf_dest: Path to a Web.config source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    tk_tag_s, _ = makeXMLTags('customHeaders')
    tk_add_tag, _ = makeXMLTags('add')
    tk_clear_tag, _ = makeXMLTags('clear')
    tk_remove_tag, _ = makeXMLTags('remove')
    tk_remove_tag.setParseAction(withAttribute(name='X-Powered-By'))
    tk_child_tag = MatchFirst(
        [Suppress(tk_add_tag),
         Suppress(tk_clear_tag), tk_remove_tag])
    result = False
    try:
        custom_headers = lang.check_grammar(tk_tag_s, webconf_dest,
                                            LANGUAGE_SPECS, exclude)
        if not custom_headers:
            show_unknown('Not files matched',
                         details=dict(code_dest=webconf_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist',
                     details=dict(code_dest=webconf_dest))
        return False

    tk_rem = Suppress(tk_tag_s) + OneOrMore(tk_child_tag)

    vulns = {}
    for code_file, val in custom_headers.items():
        vulns.update(
            lang.block_contains_empty_grammar(tk_rem, code_file, val['lines'],
                                              _get_block))
    if vulns:
        show_open('Header "X-Powered-By" is present',
                  details=dict(matched=vulns, total_lines=len(custom_headers)))
        result = True
    else:
        show_close('Header "X-Powered-By" is not present',
                   details=dict(file=webconf_dest,
                                fingerprint=get_sha256(webconf_dest)))
    return result
コード例 #12
0
ファイル: csharp.py プロジェクト: jvasque6/asserts
def swallows_exceptions(csharp_dest: str, exclude: list = None) -> bool:
    """
    Search for ``catch`` blocks that are empty or only have comments.

    See `REQ.161 <https://fluidattacks.com/web/rules/161/>`_.

    :param csharp_dest: Path to a C# source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    tk_catch = CaselessKeyword('catch')
    tk_word = Word(alphas)
    parser_catch = (Optional(Literal('}')) + tk_catch + Literal('(') +
                    tk_word + Optional(Literal('(') + tk_word + Literal(')')) +
                    Optional(tk_word) + Literal(')'))
    empty_catch = (Suppress(parser_catch) +
                   nestedExpr(opener='{', closer='}')).ignore(cppStyleComment)

    result = False
    try:
        catches = lang.check_grammar(parser_catch, csharp_dest, LANGUAGE_SPECS,
                                     exclude)
        if not catches:
            show_close('Code does not have catches',
                       details=dict(code_dest=csharp_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist',
                     details=dict(code_dest=csharp_dest))
        return False
    vulns = {}
    for code_file, val in catches.items():
        vulns.update(
            lang.block_contains_empty_grammar(empty_catch, code_file,
                                              val['lines'],
                                              _get_block_as_one_liner))
    if not vulns:
        show_close('Code does not have empty catches',
                   details=dict(file=csharp_dest,
                                fingerprint=get_sha256(csharp_dest)))
    else:
        show_open('Code has empty catches',
                  details=dict(matches=vulns, total_vulns=len(vulns)))
        result = True
    return result
コード例 #13
0
ファイル: csharp.py プロジェクト: jvasque6/asserts
def has_if_without_else(csharp_dest: str, exclude: list = None) -> bool:
    r"""
    Check if all ``if``\ s have an ``else`` clause.

    See `REQ.161 <https://fluidattacks.com/web/rules/161/>`_.

    :param csharp_dest: Path to a C# source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    tk_if = CaselessKeyword('if')
    tk_else = CaselessKeyword('else')
    block = nestedExpr(opener='{', closer='}')
    prsr_if = tk_if + nestedExpr() + block
    prsr_else = Suppress(tk_else) + (prsr_if | block)
    if_head = tk_if + nestedExpr() + Optional(Literal('{'))
    if_wout_else = (Suppress(prsr_if) + prsr_else).ignore(cppStyleComment)

    result = False
    try:
        conds = lang.check_grammar(if_head, csharp_dest, LANGUAGE_SPECS,
                                   exclude)
        if not conds:
            show_close('Code does not have conditionals',
                       details=dict(code_dest=csharp_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist',
                     details=dict(code_dest=csharp_dest))
        return False
    vulns = {}
    for code_file, val in conds.items():
        vulns.update(
            lang.block_contains_empty_grammar(if_wout_else, code_file,
                                              val['lines'],
                                              _get_block_as_one_liner))
    if not vulns:
        show_close('Code has "if" with "else" clauses',
                   details=dict(file=csharp_dest,
                                fingerprint=get_sha256(csharp_dest)))
    else:
        show_open('Code does not have "if" with "else" clauses',
                  details=dict(matched=vulns, total_vulns=len(vulns)))
        result = True
    return result
コード例 #14
0
def has_debug_enabled(webconf_dest: str, exclude: list = None) -> bool:
    """
    Check if debug flag is enabled in Web.config.

    Search for debug tag in compilation section in a Web.config source file
    or package.

    :param webconf_dest: Path to a Web.config source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    tk_tag_s, _ = makeXMLTags('system.web')
    tk_compilation, _ = makeXMLTags('compilation')
    tag_no_comm = tk_compilation.ignore(htmlComment)
    tk_comp_debug = copy(tag_no_comm)
    tk_comp_debug.setParseAction(withAttribute(debug='true'))
    result = False
    try:
        sysweb_tag = lang.check_grammar(tk_tag_s, webconf_dest, LANGUAGE_SPECS,
                                        exclude)
        if not sysweb_tag:
            show_unknown('Not files matched',
                         details=dict(code_dest=webconf_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist',
                     details=dict(code_dest=webconf_dest))
        return False

    debug_tags = {}
    for code_file, val in sysweb_tag.items():
        debug_tags.update(
            lang.block_contains_grammar(tk_comp_debug, code_file, val['lines'],
                                        _get_block))
    if debug_tags:
        show_open('Debug is enabled',
                  details=dict(matched=debug_tags,
                               total_lines=len(sysweb_tag)))
        result = True
    else:
        show_close('Debug is disabled',
                   details=dict(file=webconf_dest,
                                fingerprint=get_sha256(webconf_dest)))
    return result
コード例 #15
0
ファイル: rpgle.py プロジェクト: jvasque6/asserts
def swallows_exceptions(rpg_dest: str, exclude: list = None) -> bool:
    """
    Search for on-error without code.

    See `REQ.075
    <https://fluidattacks.com/web/rules/075>`_.

    :param rpg_dest: Path to a RPG source or directory.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    tk_on = CaselessKeyword('on')
    tk_error = CaselessKeyword('error')
    tk_code = Word(nums)
    tk_monitor = tk_on + Literal('-') + tk_error + Optional(tk_code) + \
        Literal(';')
    tk_end_mon = CaselessKeyword('endmon') + Literal(';')
    prs_sw = (tk_monitor + tk_end_mon).ignore(cppStyleComment)
    result = False
    try:
        matches = lang.check_grammar(tk_monitor, rpg_dest, LANGUAGE_SPECS,
                                     exclude)
        if not matches:
            show_unknown('Code does not have error handling',
                         details=dict(code_dest=rpg_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=rpg_dest))
        return False
    vulns = {}
    for code_file, val in matches.items():
        vulns.update(
            lang.block_contains_grammar(prs_sw, code_file, val['lines'],
                                        _get_block))
    if vulns:
        show_open('Code swallows exceptions',
                  details=dict(matched=vulns, total_vulns=len(vulns)))
        result = True
    else:
        show_close('Code does not swallow exceptions',
                   details=dict(file=rpg_dest,
                                fingerprint=get_sha256(rpg_dest)))
    return result
コード例 #16
0
def not_custom_errors(webconf_dest: str, exclude: list = None) -> bool:
    """
    Check if customErrors flag is set to off in Web.config.

    CWE-12: ASP.NET Misconfiguration: Missing Custom Error Page

    :param webconf_dest: Path to a Web.config source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    tk_tag_s, _ = makeXMLTags('system.web')
    tk_custom_errors, _ = makeXMLTags('customErrors')
    tag_no_comm = tk_custom_errors.ignore(htmlComment)
    tk_comp_custom_errors = copy(tag_no_comm)
    tk_comp_custom_errors.setParseAction(withAttribute(mode='Off'))
    result = False
    try:
        sysweb_tag = lang.check_grammar(tk_tag_s, webconf_dest, LANGUAGE_SPECS,
                                        exclude)
        if not sysweb_tag:
            show_unknown('Not files matched',
                         details=dict(code_dest=webconf_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist',
                     details=dict(code_dest=webconf_dest))
        return False

    vulns = {}
    for code_file, val in sysweb_tag.items():
        vulns.update(
            lang.block_contains_grammar(tk_comp_custom_errors, code_file,
                                        val['lines'], _get_block))
    if vulns:
        show_open('Custom errors are not enabled',
                  details=dict(matches=vulns, total_lines=len(sysweb_tag)))
        result = True
    else:
        show_close('Custom errors are enabled',
                   details=dict(file=webconf_dest,
                                fingerprint=get_sha256(webconf_dest)))
    return result
コード例 #17
0
def test_get_sha256():
    """Test add_info."""
    expected_sha256: str = \
        'e988f5d769a5fc3b32031fa46c75256f5c60647c0d958e1ca59816ba58643ecb'
    assert expected_sha256 == generic.get_sha256(
        'test/static/format/jks/open/1.jks')