Ejemplo n.º 1
0
def uses_localstorage(js_dest: str, exclude: list = None) -> bool:
    """
    Search for ``localStorage`` calls in a JavaScript source file or directory.

    :param js_dest: Path to a JavaScript source file or directory.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    method = 'window.localStorage'
    tk_object = CaselessKeyword('localstorage')
    tk_method = Word(alphanums)

    lsto = tk_object + Literal('.') + tk_method + Suppress(nestedExpr())

    result = False
    try:
        matches = lang.check_grammar(lsto, js_dest, LANGUAGE_SPECS, exclude)
        if not matches:
            show_close('Code does not use {} method'.format(method),
                       details=dict(code_dest=js_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=js_dest))
        return False
    else:
        result = True
        show_open('Code uses {} method'.format(method),
                  details=dict(matched=matches, total_vulns=len(matches)))
    return result
Ejemplo n.º 2
0
def uses_system_exit(java_dest: str, exclude: list = None) -> bool:
    """
    Search for ``System.exit`` calls in a  or package.

    :param java_dest: Path to a Java source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    method = 'System.exit'
    sys_exit = Literal(method)

    result = False
    try:
        matches = lang.check_grammar(sys_exit, java_dest, LANGUAGE_SPECS,
                                     exclude)
        if not matches:
            show_close('Code does not use {} method'.format(method),
                       details=dict(code_dest=java_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=java_dest))
        return False
    else:
        result = True
        show_open('Code uses {} method'.format(method),
                  details=dict(matched=matches,
                               total_vulns=len(matches)))
    return result
Ejemplo n.º 3
0
def has_generic_exceptions(py_dest: str, exclude: list = None) -> bool:
    """
    Search for generic exceptions in a Python script or package.

    :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')
    generic_exception = tk_except + Literal(':')

    result = False
    try:
        matches = lang.check_grammar(generic_exception, py_dest,
                                     LANGUAGE_SPECS, exclude)
        if not matches:
            show_close('Code does not use generic exceptions',
                       details=dict(code_dest=py_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=py_dest))
        return False
    else:
        result = True
        show_open('Code uses generic exceptions',
                  details=dict(file=matches, total_vulns=len(matches)))
    return result
Ejemplo n.º 4
0
def uses_insecure_hash(java_dest: str, algorithm: str,
                       exclude: list = None) -> bool:
    """
    Check if code uses an insecure hashing algorithm.

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

    :param java_dest: Path to a Java source file or package.
    :param algorithm: Insecure algorithm.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    method = 'MessageDigest.getInstance("{}")'.format(algorithm.upper())
    tk_mess_dig = CaselessKeyword('messagedigest')
    tk_get_inst = CaselessKeyword('getinstance')
    tk_alg = Literal('"') + CaselessKeyword(algorithm.lower()) + Literal('"')
    tk_params = Literal('(') + tk_alg + Literal(')')
    instance = tk_mess_dig + Literal('.') + tk_get_inst + tk_params

    result = False
    try:
        matches = lang.check_grammar(instance, java_dest, LANGUAGE_SPECS,
                                     exclude)
        if not matches:
            show_close('Code does not use {} method'.format(method),
                       details=dict(code_dest=java_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=java_dest))
        return False
    else:
        result = True
        show_open('Code uses {} method'.format(method),
                  details=dict(matched=matches,
                               total_vulns=len(matches)))
    return result
Ejemplo n.º 5
0
def has_insecure_randoms(js_dest: str, exclude: list = None) -> bool:
    r"""
    Check if code uses ``Math.Random()``\ .

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

    :param js_dest: Path to a JavaScript source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    method = 'Math.random()'
    tk_class = CaselessKeyword('math')
    tk_method = CaselessKeyword('random')
    tk_params = nestedExpr()
    call_function = tk_class + Literal('.') + tk_method + Suppress(tk_params)

    result = False
    try:
        matches = lang.check_grammar(call_function, js_dest, LANGUAGE_SPECS,
                                     exclude)
        if not matches:
            show_close('Code does not use {} method'.format(method),
                       details=dict(code_dest=js_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=js_dest))
        return False
    else:
        result = True
        show_open('Code uses {} method'.format(method),
                  details=dict(matched=matches, total_vulns=len(matches)))
    return result
Ejemplo n.º 6
0
def has_generic_exceptions(csharp_dest: str, exclude: list = None) -> bool:
    """
    Search for generic exceptions in a C# source file or package.

    :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_generic_exc = CaselessKeyword('exception')
    tk_type = Word(alphas)
    tk_object_name = Word(alphas)
    tk_object = Word(alphas)
    generic_exception = Optional(Literal('}')) + tk_catch + Literal('(') + \
        tk_generic_exc + Optional(Literal('(') + tk_type + Literal(')')) + \
        Optional(tk_object_name) + \
        Optional(Literal('(') + tk_object + Literal(')'))

    result = False
    try:
        matches = lang.check_grammar(generic_exception, csharp_dest,
                                     LANGUAGE_SPECS, exclude)
        if not matches:
            show_close('Code does not use generic exceptions',
                       details=dict(code_dest=csharp_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist',
                     details=dict(code_dest=csharp_dest))
        result = False
    else:
        result = True
        show_open('Code uses generic exceptions',
                  details=dict(matched=matches, total_vulns=len(matches)))
    return result
Ejemplo n.º 7
0
def uses_eval(js_dest: str, exclude: list = None) -> bool:
    """
    Search for ``eval()`` calls in a JavaScript file or directory.

    :param js_dest: Path to a JavaScript source file or directory.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    method = 'eval()'
    tk_method = CaselessKeyword('eval')
    call_function = tk_method + Suppress(nestedExpr())
    result = False
    try:
        matches = lang.check_grammar(call_function, js_dest, LANGUAGE_SPECS,
                                     exclude)
        if not matches:
            show_close('Code does not use {} method'.format(method),
                       details=dict(code_dest=js_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=js_dest))
        return False
    else:
        result = True
        show_open('Code uses {} method'.format(method),
                  details=dict(matched=matches, total_vulns=len(matches)))
    return result
Ejemplo n.º 8
0
def uses_ecb_encryption_mode(csharp_dest: str, exclude: list = None) -> bool:
    """
    Check if code uses ECB as encryption mode.

    :param csharp_dest: Path to a C# source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    method = "Mode = CipherMode.ECB"
    tk_eq = Literal('=')
    tk_obj = SkipTo(tk_eq)
    tk_cm = CaselessKeyword('ciphermode')
    tk_ecb = CaselessKeyword('ecb')
    call_function = tk_obj + tk_eq + tk_cm + Literal('.') + tk_ecb

    result = False
    try:
        matches = lang.check_grammar(call_function, csharp_dest,
                                     LANGUAGE_SPECS, exclude)
        if not matches:
            show_close('Code does not use {} method'.format(method),
                       details=dict(code_dest=csharp_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist',
                     details=dict(code_dest=csharp_dest))
        result = False
    else:
        result = True
        show_open('Code uses {} method'.format(method),
                  details=dict(matched=matches, total_vulns=len(matches)))
    return result
Ejemplo n.º 9
0
def uses_console_writeline(csharp_dest: str, exclude: list = None) -> bool:
    """
    Check if code uses Console.WriteLine method.

    :param csharp_dest: Path to a C# source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    method = "Console.WriteLine"
    tk_console = CaselessKeyword('console')
    tk_wrilin = CaselessKeyword('writeline')
    call_function = tk_console + Literal('.') + tk_wrilin

    result = False
    try:
        matches = lang.check_grammar(call_function, csharp_dest,
                                     LANGUAGE_SPECS, exclude)
        if not matches:
            show_close('Code does not use {} method'.format(method),
                       details=dict(code_dest=csharp_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist',
                     details=dict(code_dest=csharp_dest))
        return False
    else:
        result = True
        show_open('Code uses {} method'.format(method),
                  details=dict(matched=matches, total_vulns=len(matches)))
    return result
Ejemplo n.º 10
0
def uses_sha1_hash(csharp_dest: str, exclude: list = None) -> bool:
    """
    Check if code uses SHA1 as hashing algorithm.

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

    :param csharp_dest: Path to a C# source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    method = "new SHA1CryptoServiceProvider(), new SHA1Managed()"
    tk_new = CaselessKeyword('new')
    tk_sha1cry = CaselessKeyword('SHA1CryptoServiceProvider')
    tk_sha1man = CaselessKeyword('SHA1Managed')
    tk_params = nestedExpr()
    call_function = tk_new + MatchFirst([tk_sha1cry, tk_sha1man]) + tk_params

    result = False
    try:
        matches = lang.check_grammar(call_function, csharp_dest,
                                     LANGUAGE_SPECS, exclude)
        if not matches:
            show_close('Code does not use {} method'.format(method),
                       details=dict(code_dest=csharp_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist',
                     details=dict(code_dest=csharp_dest))
        return False
    else:
        result = True
        show_open('Code uses {} method'.format(method),
                  details=dict(matched=matches, total_vulns=len(matches)))
    return result
Ejemplo n.º 11
0
def has_generic_exceptions(rpg_dest: str, exclude: list = None) -> bool:
    """
    Search for on-error empty.

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

    :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_monitor = tk_on + Literal('-') + tk_error + Literal(';')

    result = False
    try:
        matches = lang.check_grammar(tk_monitor, rpg_dest, LANGUAGE_SPECS,
                                     exclude)
        if not matches:
            show_close('Code does not have empty monitors',
                       details=dict(code_dest=rpg_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=rpg_dest))
        return False
    else:
        result = True
        show_open('Code has empty monitors',
                  details=dict(matched=matches, total_vulns=len(matches)))
    return result
Ejemplo n.º 12
0
def has_dos_dow_sqlcod(rpg_dest: str, exclude: list = None) -> bool:
    r"""
    Search for DoS for using ``DoW SQLCOD = <ZERO>``\ .

    :param rpg_dest: Path to a RPG source or directory.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    tk_dow = CaselessKeyword('dow')
    tk_sqlcod = CaselessKeyword('sqlcod')
    tk_literal_zero = CaselessKeyword('*zeros')
    tk_zeros = MatchFirst([Literal('0'), tk_literal_zero])

    dos_dow_sqlcod = tk_dow + tk_sqlcod + Literal('=') + tk_zeros

    result = False
    try:
        matches = lang.check_grammar(dos_dow_sqlcod, rpg_dest, LANGUAGE_SPECS,
                                     exclude)
        if not matches:
            show_close('Code does not have DoS for using "DoW SQLCOD = 0"',
                       details=dict(code_dest=rpg_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=rpg_dest))
        return False
    else:
        result = True
        show_open('Code has DoS for using "DoW SQLCOD = 0"',
                  details=dict(matched=matches, total_vulns=len(matches)))
    return result
Ejemplo n.º 13
0
def not_pinned(file_dest: str, exclude: list = None) -> bool:
    """
    Check if the Dockerfile uses a ``FROM:...latest`` (unpinned) base image.

    :param file_dest: Path to the Dockerfile to be tested.
    :param exclude: Paths that contains any string from this list are ignored.
    :returns: True if unpinned (bad), False if pinned (good).
    """
    tk_from = Literal('FROM')
    tk_image = Word(alphas)
    tk_version = Literal('latest')

    pinned = tk_from + tk_image + Literal(':') + tk_version

    result = False
    try:
        matches = lang.check_grammar(pinned, file_dest,
                                     LANGUAGE_SPECS, exclude)
        if not matches:
            show_close('Dockerfile has pinned base image(s)',
                       details=dict(code_dest=file_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=file_dest))
        return False
    else:
        result = True
        show_open('Dockerfile uses unpinned base image(s)',
                  details=dict(file=matches,
                               total_vulns=len(matches)))
    return result
Ejemplo n.º 14
0
def has_unitialized_vars(rpg_dest: str, exclude: list = None) -> bool:
    """
    Search for unitialized variables.

    :param rpg_dest: Path to a RPG source or directory.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    tk_data = Keyword('D')
    tk_first = Word(alphas + "_", exact=1)
    tk_rest = Word(alphanums + "_")
    tk_vartype = Word(alphas, exact=1)
    tk_varlen = Word(nums) + Word(alphas, exact=1)
    tk_inz = CaselessKeyword('inz')
    tk_varname = tk_first + tk_rest

    unitialized = tk_data + tk_varname + Optional(tk_vartype) + \
        Optional(tk_varlen) + Optional(Word(nums)) + NotAny(tk_inz)

    result = False
    try:
        matches = lang.check_grammar(unitialized, rpg_dest, LANGUAGE_SPECS,
                                     exclude)
        if not matches:
            show_close('Code does not have unitialized variables',
                       details=dict(code_dest=rpg_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=rpg_dest))
        return False
    else:
        result = True
        show_open('Code has unitialized variables',
                  details=dict(matched=matches, total_vulns=len(matches)))
    return result
Ejemplo n.º 15
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
Ejemplo n.º 16
0
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
Ejemplo n.º 17
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
Ejemplo n.º 18
0
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
Ejemplo n.º 19
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
Ejemplo n.º 20
0
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
Ejemplo n.º 21
0
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
Ejemplo n.º 22
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
Ejemplo n.º 23
0
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
Ejemplo n.º 24
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
Ejemplo n.º 25
0
def uses_md5_hash(csharp_dest: str, exclude: list = None) -> bool:
    """
    Check if code uses MD5 as hashing algorithm.

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

    :param csharp_dest: Path to a C# source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    method = 'MD5.Create(), new MD5CryptoServiceProvider()'
    tk_md5 = CaselessKeyword('md5')
    tk_create = CaselessKeyword('create')
    tk_params = nestedExpr()
    fn_1 = tk_md5 + Literal('.') + tk_create + tk_params

    tk_new = CaselessKeyword('new')
    tk_md5cry = CaselessKeyword('MD5CryptoServiceProvider')
    tk_params = nestedExpr()
    fn_2 = tk_new + tk_md5cry + tk_params

    call_function = MatchFirst([fn_1, fn_2])

    result = False
    try:
        matches = lang.check_grammar(call_function, csharp_dest,
                                     LANGUAGE_SPECS, exclude)
        if not matches:
            show_close('Code uses {} method'.format(method),
                       details=dict(code_dest=csharp_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist',
                     details=dict(code_dest=csharp_dest))
        result = False
    else:
        result = True
        show_open('Code uses {} method'.format(method),
                  details=dict(matched=matches, total_vulns=len(matches)))
    return result
Ejemplo n.º 26
0
def has_log_injection(java_dest: str, exclude: list = None) -> bool:
    """
    Search code injection.

    Check if the code does not neutralize or incorrectly neutralizes
    output that is written to logs.

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

    :param java_dest: Path to a Java source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    log_variable = CaselessKeyword('log')
    log_level = oneOf('trace debug info warn error fatal')

    log_object = log_variable + Literal('.') + log_level

    tk_string = QuotedString('"')
    tk_var = Word(alphanums)

    pst = log_object + Literal('(') + tk_string + Literal('+') + tk_var
    result = False
    try:
        matches = lang.check_grammar(pst, java_dest, LANGUAGE_SPECS, exclude)
        if not matches:
            show_close('Code does not allow logs injection',
                       details=dict(code_dest=java_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist', details=dict(code_dest=java_dest))
        return False
    else:
        result = True
        show_open('Code allows logs injection',
                  details=dict(matched=matches,
                               total_vulns=len(matches)))
    return result
Ejemplo n.º 27
0
def has_insecure_randoms(csharp_dest: str, exclude: list = None) -> bool:
    """
    Check if code instantiates ``Random`` class.

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

    :param csharp_dest: Path to a C# source file or package.
    :param exclude: Paths that contains any string from this list are ignored.
    """
    tk_new = Keyword('new')
    tk_var = Keyword('var')
    tk_equal = Literal('=')
    tk_params = nestedExpr()
    tk_random = Keyword('Random')
    tk_variable = Word(alphas + '_', alphanums + '_')

    instantiation = (tk_var | tk_random) + tk_variable + tk_equal + tk_new + \
        tk_random + Suppress(tk_params)

    result = False
    try:
        random_new = lang.check_grammar(instantiation, csharp_dest,
                                        LANGUAGE_SPECS, exclude)
        if not random_new:
            show_close('Code does not generate insecure random numbers',
                       details=dict(code_dest=csharp_dest))
            return False
    except FileNotFoundError:
        show_unknown('File does not exist',
                     details=dict(code_dest=csharp_dest))
        result = False
    else:
        result = True
        show_open('Code generates insecure random numbers',
                  details=dict(matched=random_new,
                               total_vulns=len(random_new)))
    return result