# HG changeset patch # User jfp <jf.pieronne@laposte.net> # Date 1673621180 -3600 # Fri Jan 13 15:46:20 2023 +0100 # Node ID d052b3f28585ce273a491f2b0ff79465f619ebb4 # Parent 11940d28824c8f2576a51803b550a2f32c9d31c2 Format code using blue, remove unised IdToAsc.py diff --git a/secrules/DisplayProxy.py b/secrules/DisplayProxy.py --- a/secrules/DisplayProxy.py +++ b/secrules/DisplayProxy.py @@ -18,12 +18,20 @@ return self def __next__(self): - s, proxy_node, proxy_user, default_user, local_users, self.contxt = \ - starlet.display_proxy(self.rem_node, self.rem_user, self.flags, self.contxt) - if s == ssdef.SS__NOMOREITEMS: + ( + s, + proxy_node, + proxy_user, + default_user, + local_users, + self.contxt, + ) = starlet.display_proxy( + self.rem_node, self.rem_user, self.flags, self.contxt + ) + if s == ssdef.SS__NOMOREITEMS: raise StopIteration return proxy_node, proxy_user, default_user, local_users - + def next(self): return self.__next__() diff --git a/secrules/IdToAsc.py b/secrules/IdToAsc.py deleted file mode 100644 --- a/secrules/IdToAsc.py +++ /dev/null @@ -1,43 +0,0 @@ -from vms import starlet, ssdef - - -class IdToAsc(object): - def __init__(self): - self.contxt = 0 - self.iid = None - - def __enter__(self): - self.contxt = 0 - self.iid = 0xFFFFFFFF # do a wildcard lookup - return self - - def __exit__(self, exc_type, exc_value, traceback): - starlet.finish_rdb(self.contxt) - - def __iter__(self): - return self - - def __next__(self): - try: - s, idname, rid, attrib, self.contxt = \ - starlet.idtoasc(self.iid, self.contxt) - return self.uictoasc(rid) if (rid < 0x80000000L) else "%s" % idname - except VMSError, e: - raise StopIteration if e.errno == ssdef.SS__NOSUCHID else e - - def next(self): - return self.__next__() - - def uictoasc(self, uic_value): - high_word = int(uic_value / 65536) - low_word = int(uic_value - (high_word * 65536)) - # Note: [1:], because octal values will be preceeded by '0' - high_word = '0' if high_word == 0 else oct(high_word)[1:] - low_word = '0' if low_word == 0 else oct(low_word)[1:] - return '[' + high_word + ',' + low_word + ']' - - -if __name__ == '__main__': - with IdToAsc() as iid: - for idnam in iid: - print idnam diff --git a/secrules/common.py b/secrules/common.py --- a/secrules/common.py +++ b/secrules/common.py @@ -3,11 +3,15 @@ import functools + def level_rule(level=1): def decorator_rule_level(func): func.rule_level = level + @functools.wraps(func) def wrapper_decorator(*args, **kwargs): return func(*args, **kwargs) + return wrapper_decorator + return decorator_rule_level diff --git a/secrules/getMailObjectInfo.py b/secrules/getMailObjectInfo.py --- a/secrules/getMailObjectInfo.py +++ b/secrules/getMailObjectInfo.py @@ -7,6 +7,7 @@ VMSError = OSError + def getMailObjectInfo() -> Tuple[bool, bool, user.User | None]: all_users = user.all_users() maxsysgroup = lib.getsyi(syidef.SYI__MAXSYSGROUP)[1] diff --git a/secrules/get_mail_info.py b/secrules/get_mail_info.py --- a/secrules/get_mail_info.py +++ b/secrules/get_mail_info.py @@ -6,13 +6,14 @@ VMSError = OSError + def getMailObjectInfo(): all_users = user.all_users() maxsysgroup = lib.getsyi(syidef.SYI__MAXSYSGROUP)[1] def file_exists(fn): try: - with FindFile (fn) as ifn: + with FindFile(fn) as ifn: ifn.__next__() return True except VMSError as e: diff --git a/secrules/get_security.py b/secrules/get_security.py --- a/secrules/get_security.py +++ b/secrules/get_security.py @@ -2,10 +2,17 @@ from ovms import itemList, ossdef, ssdef from ovms.rtl import lib + def get_security(fn, clsnam=b'FILE'): - itm = (itemList.itemList (code=ossdef.OSS__ACL_READ), - itemList.itemList (code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedWord), - itemList.itemList (code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong)) + itm = ( + itemList.itemList(code=ossdef.OSS__ACL_READ), + itemList.itemList( + code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedWord + ), + itemList.itemList( + code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong + ), + ) accnam = lib.get_accnam(clsnam)[1] s, ctxt, res = starlet.get_security(clsnam, fn, itmlst=itm) @@ -14,18 +21,24 @@ except: own: int = res[ossdef.OSS__OWNER] # type: ignore high_word = int(own / 65536) - low_word = int(own - (high_word *65536)) - ownstr = b"[%o,%o]" % (high_word, low_word) - prot = lib.format_sogw_prot(res[ossdef.OSS__PROTECTION], access_names=accnam)[1] # type: ignore + low_word = int(own - (high_word * 65536)) + ownstr = b'[%o,%o]' % (high_word, low_word) + prot = lib.format_sogw_prot( + res[ossdef.OSS__PROTECTION], access_names=accnam + )[ + 1 + ] # type: ignore acl = [] v: bytes = res[ossdef.OSS__ACL_READ] # type: ignore while v != b'': - acl.append(starlet.format_acl(v[:v[0]], accnam=accnam)[1]) - v = v[v[0]:] + acl.append(starlet.format_acl(v[: v[0]], accnam=accnam)[1]) + v = v[v[0] :] return ownstr, prot, acl + if __name__ == '__main__': import sys + filename = sys.argv[1] clsnam = sys.argv[2] owner, protection, acl = get_security(filename, clsnam.encode()) @@ -33,4 +46,4 @@ print(' Protection:', protection) print(' Access control list:') for e in acl: - print(9*' ', e) + print(9 * ' ', e) diff --git a/secrules/rules01.py b/secrules/rules01.py --- a/secrules/rules01.py +++ b/secrules/rules01.py @@ -1,6 +1,6 @@ # -*- coding: iso-8859-1 -*- __version__ = '1.0' -#__all__ = ['rule1201', 'rule1202', 'rule1203'] +# __all__ = ['rule1201', 'rule1202', 'rule1203'] from .common import level_rule from ovms.rtl import lib @@ -10,12 +10,13 @@ from ovms import itemList from ovms import crtl + @level_rule(1) def rule0101(fo, ftm): """The following system-level accounts do not have account restrictions defined. -Improper configuration of access restrictions could result in the compromise of -the operating system environment, and compromise the confidentiality of customer data""" + Improper configuration of access restrictions could result in the compromise of + the operating system environment, and compromise the confidentiality of customer data""" maxsysgroup = lib.getsyi(syidef.SYI__MAXSYSGROUP)[1] all_users = user.all_users() @@ -23,18 +24,29 @@ if not ftm: print('Rule 0101', file=fo) print('=========', file=fo) - for u in list(all_users.values()): - if (u.uic_group <= maxsysgroup) and (u.dialup_access_p != '\xff\xff\xff'): + for u in list(all_users.values()): + if (u.uic_group <= maxsysgroup) and ( + u.dialup_access_p != '\xff\xff\xff' + ): if ftm: - print('0101"1" %-12s [%o,%o]' % (u.username.decode(), u.uic_group, u.uic_member), file=fo) + print( + '0101"1" %-12s [%o,%o]' + % (u.username.decode(), u.uic_group, u.uic_member), + file=fo, + ) else: - print('%-12s [%o,%o]' % (u.username.decode(), u.uic_group, u.uic_member), file=fo) + print( + '%-12s [%o,%o]' + % (u.username.decode(), u.uic_group, u.uic_member), + file=fo, + ) + @level_rule(2) def rule0102(fo, ftm): - """The accounts listed have duplicate UICs. This is a security problem. -Accounts that share a common UIC allow the user of one account -to modify or delete the files of another account""" + """The accounts listed have duplicate UICs. This is a security problem. + Accounts that share a common UIC allow the user of one account + to modify or delete the files of another account""" all_users = user.all_users() @@ -43,24 +55,27 @@ print('Rule 0102', file=fo) print('=========', file=fo) uics = {} - for u in list(all_users.values()): + for u in list(all_users.values()): uic = '[%o,%o]' % (u.uic_group, u.uic_member) if uic in uics: uics[uic].append(u.username) else: - uics[uic] = [u.username,] - + uics[uic] = [ + u.username, + ] + for uic in uics: if len(uics[uic]) > 1: if ftm: print('0102"2"', uic, uics[uic], file=fo) else: print(uic, uics[uic], file=fo) - + + @level_rule(3) def rule0103(fo, ftm): - """Most accounts with these types of privileges are not part of the normal -operating system distribution and can represent a security risk.""" + """Most accounts with these types of privileges are not part of the normal + operating system distribution and can represent a security risk.""" maxsysgroup = lib.getsyi(syidef.SYI__MAXSYSGROUP)[1] all_users = user.all_users() @@ -70,21 +85,24 @@ print('Rule 0103', file=fo) print('=========', file=fo) for u in list(all_users.values()): - if (u.uic_group <= maxsysgroup): - if (u.priv | u.def_priv) & (prvdef.PRV_M_GROUP | prvdef.PRV_M_GRPPRV): + if u.uic_group <= maxsysgroup: + if (u.priv | u.def_priv) & ( + prvdef.PRV_M_GROUP | prvdef.PRV_M_GRPPRV + ): if ftm: print('0103"3"', u.username.decode(), file=fo) else: print(u.username.decode(), file=fo) + @level_rule(3) def rule0104(fo, ftm): - """A system level UIC is one in which the group number is less than, -or equal to, the SYSGEN parameter, MAXSYSGROUP. The group number is -defined at system generation time and may vary from site to site. -Account privileges allow users to add, modify or delete system files. -These accounts are not part of the normal operating -system distribution and can represent a security risk.""" + """A system level UIC is one in which the group number is less than, + or equal to, the SYSGEN parameter, MAXSYSGROUP. The group number is + defined at system generation time and may vary from site to site. + Account privileges allow users to add, modify or delete system files. + These accounts are not part of the normal operating + system distribution and can represent a security risk.""" maxsysgroup = lib.getsyi(syidef.SYI__MAXSYSGROUP)[1] all_users = user.all_users() @@ -99,13 +117,14 @@ print('0104"3"', u.username.decode(), file=fo) else: print(u.username.decode(), file=fo) - + + @level_rule(3) def rule0105(fo, ftm): - """Improperly granted privilege classes can grant unintended -privileges and accesses to users. This could result in the -compromise of the operating system environment, and compromise -the confidentiality of customer data.""" + """Improperly granted privilege classes can grant unintended + privileges and accesses to users. This could result in the + compromise of the operating system environment, and compromise + the confidentiality of customer data.""" maxsysgroup = lib.getsyi(syidef.SYI__MAXSYSGROUP)[1] all_users = user.all_users() @@ -115,56 +134,59 @@ print('Rule 0105', file=fo) print('=========', file=fo) - privs = (prvdef.PRV_M_CMKRNL | - prvdef.PRV_M_CMEXEC | - prvdef.PRV_M_SYSNAM | - prvdef.PRV_M_GRPNAM | - prvdef.PRV_M_ALLSPOOL | - prvdef.PRV_M_IMPERSONATE | - prvdef.PRV_M_DIAGNOSE | - prvdef.PRV_M_LOG_IO | - prvdef.PRV_M_GROUP | - prvdef.PRV_M_NOACNT | - prvdef.PRV_M_PRMCEB | - prvdef.PRV_M_PRMMBX | - prvdef.PRV_M_PSWAPM | - prvdef.PRV_M_SETPRI | - prvdef.PRV_M_SETPRV | - prvdef.PRV_M_WORLD | - prvdef.PRV_M_MOUNT | - prvdef.PRV_M_OPER | - prvdef.PRV_M_EXQUOTA | - prvdef.PRV_M_VOLPRO | - prvdef.PRV_M_PHY_IO | - prvdef.PRV_M_BUGCHK | - prvdef.PRV_M_PRMGBL | - prvdef.PRV_M_SYSGBL | - prvdef.PRV_M_PFNMAP | - prvdef.PRV_M_SHMEM | - prvdef.PRV_M_SYSPRV | - prvdef.PRV_M_BYPASS | - prvdef.PRV_M_SYSLCK | - prvdef.PRV_M_SHARE | - prvdef.PRV_M_UPGRADE | - prvdef.PRV_M_DOWNGRADE | - prvdef.PRV_M_GRPPRV | - prvdef.PRV_M_READALL | - prvdef.PRV_M_IMPORT | - prvdef.PRV_M_AUDIT | - prvdef.PRV_M_SECURITY) - + privs = ( + prvdef.PRV_M_CMKRNL + | prvdef.PRV_M_CMEXEC + | prvdef.PRV_M_SYSNAM + | prvdef.PRV_M_GRPNAM + | prvdef.PRV_M_ALLSPOOL + | prvdef.PRV_M_IMPERSONATE + | prvdef.PRV_M_DIAGNOSE + | prvdef.PRV_M_LOG_IO + | prvdef.PRV_M_GROUP + | prvdef.PRV_M_NOACNT + | prvdef.PRV_M_PRMCEB + | prvdef.PRV_M_PRMMBX + | prvdef.PRV_M_PSWAPM + | prvdef.PRV_M_SETPRI + | prvdef.PRV_M_SETPRV + | prvdef.PRV_M_WORLD + | prvdef.PRV_M_MOUNT + | prvdef.PRV_M_OPER + | prvdef.PRV_M_EXQUOTA + | prvdef.PRV_M_VOLPRO + | prvdef.PRV_M_PHY_IO + | prvdef.PRV_M_BUGCHK + | prvdef.PRV_M_PRMGBL + | prvdef.PRV_M_SYSGBL + | prvdef.PRV_M_PFNMAP + | prvdef.PRV_M_SHMEM + | prvdef.PRV_M_SYSPRV + | prvdef.PRV_M_BYPASS + | prvdef.PRV_M_SYSLCK + | prvdef.PRV_M_SHARE + | prvdef.PRV_M_UPGRADE + | prvdef.PRV_M_DOWNGRADE + | prvdef.PRV_M_GRPPRV + | prvdef.PRV_M_READALL + | prvdef.PRV_M_IMPORT + | prvdef.PRV_M_AUDIT + | prvdef.PRV_M_SECURITY + ) + for u in list(all_users.values()): - if (u.uic_group > maxsysgroup): + if u.uic_group > maxsysgroup: if (u.priv | u.def_priv) & privs: if ftm: print('0105"3"', u.username.decode(), file=fo) else: print(u.username.decode(), file=fo) - + + @level_rule(3) def rule0106(fo, ftm): - """These accounts may no longer be valid or useful, and may -represent a security exposure to the system.""" + """These accounts may no longer be valid or useful, and may + represent a security exposure to the system.""" all_users = user.all_users() @@ -181,10 +203,11 @@ else: print(u.username.decode(), u.defdev.decode(), file=fo) + @level_rule(3) def rule0107(fo, ftm): - """The device may not be online, mounted or available. -Security checks cannot be completed.""" + """The device may not be online, mounted or available. + Security checks cannot be completed.""" all_users = user.all_users() @@ -201,12 +224,13 @@ else: print(u.username.decode(), u.defdev.decode(), file=fo) + @level_rule(2) def rule0108(fo, ftm): - """Improper home directory configuration can interfere with -the proper functioning of accounts. The accounts listed do not -have home directories. This is not consistent with the system -configuration. These accounts may be inactive or DISUSERed.""" + """Improper home directory configuration can interfere with + the proper functioning of accounts. The accounts listed do not + have home directories. This is not consistent with the system + configuration. These accounts may be inactive or DISUSERed.""" all_users = user.all_users() @@ -221,11 +245,12 @@ else: print(u.username.decode(), file=fo) + @level_rule(3) def rule0109(fo, ftm): - """Improper account ownership can prevent proper identification -of assigned privileges, result in auditing difficulties, and can -jeopardize overall system security.""" + """Improper account ownership can prevent proper identification + of assigned privileges, result in auditing difficulties, and can + jeopardize overall system security.""" all_users = user.all_users() @@ -233,72 +258,93 @@ print(file=fo) print('Rule 0109', file=fo) print('=========', file=fo) - + privs = prvdef.PRV_M_TMPMBX | prvdef.PRV_M_NETMBX u = all_users[b'DEFAULT'] - if (u.def_priv != u.priv) or (u.priv & ~privs) or (u.flags & uaidef.UAI_M_DISACNT) == 0: + if ( + (u.def_priv != u.priv) + or (u.priv & ~privs) + or (u.flags & uaidef.UAI_M_DISACNT) == 0 + ): if ftm: print('0109"3"', u.username.decode(), file=fo) else: print(u.username.decode(), file=fo) - - privs = (prvdef.PRV_M_TMPMBX | - prvdef.PRV_M_NETMBX | - prvdef.PRV_M_ALLSPOOL | - prvdef.PRV_M_DIAGNOSE | - prvdef.PRV_M_PHY_IO | - prvdef.PRV_M_GROUP | - prvdef.PRV_M_PRMCEB | - prvdef.PRV_M_GRPNAM | - prvdef.PRV_M_PRMMBX | - prvdef.PRV_M_LOG_IO | - prvdef.PRV_M_SETPRV) + + privs = ( + prvdef.PRV_M_TMPMBX + | prvdef.PRV_M_NETMBX + | prvdef.PRV_M_ALLSPOOL + | prvdef.PRV_M_DIAGNOSE + | prvdef.PRV_M_PHY_IO + | prvdef.PRV_M_GROUP + | prvdef.PRV_M_PRMCEB + | prvdef.PRV_M_GRPNAM + | prvdef.PRV_M_PRMMBX + | prvdef.PRV_M_LOG_IO + | prvdef.PRV_M_SETPRV + ) if b'FIELD' in all_users: u = all_users[b'FIELD'] - if (u.def_priv != u.priv) or (u.priv & ~privs) or (u.flags & uaidef.UAI_M_DISACNT) == 0: + if ( + (u.def_priv != u.priv) + or (u.priv & ~privs) + or (u.flags & uaidef.UAI_M_DISACNT) == 0 + ): if ftm: print('0109"3"', u.username.decode(), file=fo) else: print(u.username.decode(), file=fo) - - privs = (prvdef.PRV_M_CMEXEC | - prvdef.PRV_M_IMPERSONATE | - prvdef.PRV_M_PRMMBX | - prvdef.PRV_M_VOLPRO | - prvdef.PRV_M_CMKRNL | - prvdef.PRV_M_LOG_IO | - prvdef.PRV_M_SETPRV | - prvdef.PRV_M_DIAGNOSE | - prvdef.PRV_M_NETMBX | - prvdef.PRV_M_SYSNAM | - prvdef.PRV_M_GROUP | - prvdef.PRV_M_PHY_IO | - prvdef.PRV_M_SYSPRV | - prvdef.PRV_M_GRPNAM | - prvdef.PRV_M_PRMCEB | - prvdef.PRV_M_TMPMBX) - + + privs = ( + prvdef.PRV_M_CMEXEC + | prvdef.PRV_M_IMPERSONATE + | prvdef.PRV_M_PRMMBX + | prvdef.PRV_M_VOLPRO + | prvdef.PRV_M_CMKRNL + | prvdef.PRV_M_LOG_IO + | prvdef.PRV_M_SETPRV + | prvdef.PRV_M_DIAGNOSE + | prvdef.PRV_M_NETMBX + | prvdef.PRV_M_SYSNAM + | prvdef.PRV_M_GROUP + | prvdef.PRV_M_PHY_IO + | prvdef.PRV_M_SYSPRV + | prvdef.PRV_M_GRPNAM + | prvdef.PRV_M_PRMCEB + | prvdef.PRV_M_TMPMBX + ) + if b'SYSTEST' in all_users: u = all_users[b'SYSTEST'] - if (u.def_priv != u.priv) or (u.priv & ~privs) or (u.flags & uaidef.UAI_M_DISACNT) == 0: + if ( + (u.def_priv != u.priv) + or (u.priv & ~privs) + or (u.flags & uaidef.UAI_M_DISACNT) == 0 + ): if ftm: print('0109"3"', u.username, file=fo) else: print(u.username, file=fo) - + if b'SYSTEST_CLIG' in all_users: u = all_users[b'SYSTEST_CLIG'] - if (u.def_priv != u.priv) or (u.priv & ~privs) or (u.flags & uaidef.UAI_M_DISACNT) == 0: + if ( + (u.def_priv != u.priv) + or (u.priv & ~privs) + or (u.flags & uaidef.UAI_M_DISACNT) == 0 + ): if ftm: print('0109"3"', u.username.decode(), file=fo) else: print(u.username.decode(), file=fo) - + + @level_rule(3) def rule0110(fo, ftm): - """ Improper configuration of account related SYSGEN parameters -could result in the compromise of the operating system environment, -and compromise the confidentiality of customer data.""" + """Improper configuration of account related SYSGEN parameters + could result in the compromise of the operating system environment, + and compromise the confidentiality of customer data.""" maxsysgroup = lib.getsyi(syidef.SYI__MAXSYSGROUP)[1] @@ -306,30 +352,43 @@ print(file=fo) print('Rule 0110', file=fo) print('=========', file=fo) - + load_pwd_policy = lib.getsyi(syidef.SYI__LOAD_PWD_POLICY)[1] rms_fileprot = lib.getsyi(syidef.SYI__RMS_FILEPROT)[1] - - if (load_pwd_policy != 0): + + if load_pwd_policy != 0: if ftm: - print('0110"3"LOAD_PWD_POLICY', load_pwd_policy, file=fo) + print('0110"3"LOAD_PWD_POLICY', load_pwd_policy, file=fo) else: - print('LOAD_PWD_POLICY invalid', load_pwd_policy, file=fo) - if (maxsysgroup > 8): + print('LOAD_PWD_POLICY invalid', load_pwd_policy, file=fo) + if maxsysgroup > 8: if ftm: print('0110"3"MAXSYSGROUP', maxsysgroup, file=fo) else: - print('MAXSYSGROUP invalid' , maxsysgroup, file=fo) - if (rms_fileprot not in (64000, 65280)): + print('MAXSYSGROUP invalid', maxsysgroup, file=fo) + if rms_fileprot not in (64000, 65280): if ftm: - print('0110"3"RMS_FILEPROT', lib.format_sogw_prot(rms_fileprot)[1], file=fo) + print( + '0110"3"RMS_FILEPROT', + lib.format_sogw_prot(rms_fileprot)[1], + file=fo, + ) else: - print('RMS_FILEPROT invalid found', lib.format_sogw_prot(rms_fileprot)[1].decode(), file=fo) - print(' waiting', lib.format_sogw_prot(65280)[1].decode(), file=fo) - - + print( + 'RMS_FILEPROT invalid found', + lib.format_sogw_prot(rms_fileprot)[1].decode(), + file=fo, + ) + print( + ' waiting', + lib.format_sogw_prot(65280)[1].decode(), + file=fo, + ) + + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule0101(fo, len(sys.argv) > 2) rule0102(fo, len(sys.argv) > 2) diff --git a/secrules/rules02.py b/secrules/rules02.py --- a/secrules/rules02.py +++ b/secrules/rules02.py @@ -13,14 +13,15 @@ VMSError = OSError + @level_rule(2) def rule0201(fo, fmt): - """ Improper system file access could result in the compromise of -the operating system environment, and compromise the confidentiality -of customer data. The files listed are accessible by non-privileged -users as indicated. This allows non-privileged users to read, execute, -modify, or delete the files. Users can gain access using an ACL granted -to the user, the privilege of the user, or the UIC protection on the file.""" + """Improper system file access could result in the compromise of + the operating system environment, and compromise the confidentiality + of customer data. The files listed are accessible by non-privileged + users as indicated. This allows non-privileged users to read, execute, + modify, or delete the files. Users can gain access using an ACL granted + to the user, the privilege of the user, or the UIC protection on the file.""" if not fmt: print(file=fo) @@ -29,28 +30,42 @@ with FindFile(b'SYS$SYSROOT:[000000...]*.*') as fi: for fn in fi: - it = (itemList.itemList(code = ossdef.OSS__PROTECTION, dtype = itemList.il_unsignedWord),) + it = ( + itemList.itemList( + code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedWord + ), + ) try: - sec: int = starlet.get_security(objnam=fn, clsnam='FILE', # type:ignore - itmlst=it)[2][ossdef.OSS__PROTECTION] # type:ignore + sec: int = starlet.get_security( + objnam=fn, + clsnam='FILE', # type:ignore + itmlst=it, + )[2][ + ossdef.OSS__PROTECTION + ] # type:ignore if not ((sec & 0x8000) and (sec & 0x2000)): if fmt: print('0201"2"', fn, file=fo) else: print(fn.decode(), file=fo) # type:ignore - print(' ' * 10, lib.format_sogw_prot (sec)[1].decode(), file=fo) + print( + ' ' * 10, + lib.format_sogw_prot(sec)[1].decode(), + file=fo, + ) except VMSError as e: if e.errno != ssdef.SS__NOSUCHFILE: raise + @level_rule(3) def rule0202(fo, fmt): - """ Improper system file access could result in the compromise of the -operating system environment, and compromise the confidentiality of customer -data. The listed files are accessible by privileged users as indicated. -This allows privileged users to read, execute, modify, or delete the files. -Users can gain access using an ACL granted to the user, the privilege of the -user, or the UIC protection on the file.""" + """Improper system file access could result in the compromise of the + operating system environment, and compromise the confidentiality of customer + data. The listed files are accessible by privileged users as indicated. + This allows privileged users to read, execute, modify, or delete the files. + Users can gain access using an ACL granted to the user, the privilege of the + user, or the UIC protection on the file.""" if not fmt: print(file=fo) @@ -60,17 +75,31 @@ with FindFile(b'SYS$SYSROOT:[000000...]*.*') as fi: for fn in fi: # type:ignore fn: bytes - it = (itemList.itemList (code = ossdef.OSS__PROTECTION, dtype = itemList.il_unsignedWord),) - sec: int = starlet.get_security(objnam=fn, clsnam='FILE',itmlst=it)[2][ossdef.OSS__PROTECTION] # type:ignore + it = ( + itemList.itemList( + code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedWord + ), + ) + sec: int = starlet.get_security( + objnam=fn, clsnam='FILE', itmlst=it + )[2][ + ossdef.OSS__PROTECTION + ] # type:ignore if not ((sec & 0x800) and (sec & 0x200)): if fmt: print('0202"3"', fn.decode(), file=fo) # type:ignore else: print(fn.decode(), file=fo) # type:ignore - print(' ' * 10, lib.format_sogw_prot(sec)[1].decode(), file=fo) + print( + ' ' * 10, + lib.format_sogw_prot(sec)[1].decode(), + file=fo, + ) + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule0201(fo, len(sys.argv) > 2) rule0202(fo, len(sys.argv) > 2) diff --git a/secrules/rules03.py b/secrules/rules03.py --- a/secrules/rules03.py +++ b/secrules/rules03.py @@ -5,11 +5,12 @@ from ovms.rtl.lib.FindFile import FindFile from .get_security import get_security + @level_rule(2) def rule0302(fo, fmt): - """ If the change was not approved by the system manager, then it -signifies an unauthorized change was made to the file, and represents an area -of vulnerability with regards to protection of critical files.""" + """If the change was not approved by the system manager, then it + signifies an unauthorized change was made to the file, and represents an area + of vulnerability with regards to protection of critical files.""" if not fmt: print(file=fo) @@ -28,7 +29,9 @@ print(fn.decode(), file=fo) print(' ' * 10, id.decode(), file=fo) + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule0302(fo, len(sys.argv) > 2) diff --git a/secrules/rules04.py b/secrules/rules04.py --- a/secrules/rules04.py +++ b/secrules/rules04.py @@ -14,155 +14,182 @@ VMSError = OSError + @level_rule(2) def rule0401(fo, fmt): - """ The integrity of system files is critical to the security and -integrity of the VMS operating environment. Improperly defined ACLs can -grant unintended access to files, which could result in the compromise of -the operating environment, and/or compromise the confidentiality of customer -data.""" + """The integrity of system files is critical to the security and + integrity of the VMS operating environment. Improperly defined ACLs can + grant unintended access to files, which could result in the compromise of + the operating environment, and/or compromise the confidentiality of customer + data.""" if not fmt: print(file=fo) print('Rule 0401', file=fo) print('=========', file=fo) - + def fileACL(root): - it = (itemList.itemList (code=ossdef.OSS__ACL_LENGTH, dtype=itemList.il_unsignedLong),) + it = ( + itemList.itemList( + code=ossdef.OSS__ACL_LENGTH, dtype=itemList.il_unsignedLong + ), + ) with FindFile(root) as ifn: - for fn in ifn: # type:ignore + for fn in ifn: # type:ignore fn: bytes try: - retacl = starlet.get_security(objnam=fn, clsnam='FILE',itmlst=it) - acllen = int(retacl[2][ossdef.OSS__ACL_LENGTH]) - if (acllen != 0): + retacl = starlet.get_security( + objnam=fn, clsnam='FILE', itmlst=it + ) + acllen = int(retacl[2][ossdef.OSS__ACL_LENGTH]) + if acllen != 0: if fmt: print('0401"2"', fn.decode(), file=fo) else: print(fn.decode(), file=fo) - for e in get_security.get_security (fn)[2]: + for e in get_security.get_security(fn)[2]: e: bytes if not fmt: - print(' '*9, e.decode(), file=fo) + print(' ' * 9, e.decode(), file=fo) except VMSError as err: - if err.errno not in (rmsdef.RMS__FNF, ssdef.SS__NOSUCHFILE): + if err.errno not in ( + rmsdef.RMS__FNF, + ssdef.SS__NOSUCHFILE, + ): raise - + for device in DeviceScan(b'*', devclass=dcdef.DC__DISK): - if not (lib.getdvi (dvidef.DVI__MNT, device_name=device)[1]): + if not (lib.getdvi(dvidef.DVI__MNT, device_name=device)[1]): continue - if lib.getdvi (dvidef.DVI__SHDW_MEMBER, device_name=device)[1]: + if lib.getdvi(dvidef.DVI__SHDW_MEMBER, device_name=device)[1]: continue fileACL(device + b'[000000...]*.*') - + + @level_rule(2) def rule0403(fo, fmt): - """ From a security standpoint, this is extremely dangerous because -it can render the disk unusable or the system inoperable because these -files can be corrupted or deleted.""" + """From a security standpoint, this is extremely dangerous because + it can render the disk unusable or the system inoperable because these + files can be corrupted or deleted.""" if not fmt: print(file=fo) print('Rule 0403', file=fo) print('=========', file=fo) - + def fileSYS(root): with FindFile(root) as fi: - for fn in fi: # type: ignore + for fn in fi: # type: ignore fn: bytes - own = get_security.get_security(fn)[0] + own = get_security.get_security(fn)[0] if own not in ('SYSTEM', '[1,1]'): if fmt: print('0403"2"', fn.decode(), file=fo) else: - print(fn.decode(), own.decode(), file=fo) + print(fn.decode(), own.decode(), file=fo) devCtx = 0 - devItm = (itemList.itemList (code=dvsdef.DVS__DEVCLASS, value=dcdef.DC__DISK),) - - while(True): + devItm = ( + itemList.itemList(code=dvsdef.DVS__DEVCLASS, value=dcdef.DC__DISK), + ) + + while True: try: - sts,device,devCtx = starlet.device_scan(b'*', devItm, devCtx) + sts, device, devCtx = starlet.device_scan(b'*', devItm, devCtx) except: break - if not lib.getdvi (dvidef.DVI__MNT, device_name=device)[1]: + if not lib.getdvi(dvidef.DVI__MNT, device_name=device)[1]: continue if lib.getdvi(dvidef.DVI__SHDW_MEMBER, device_name=device)[1]: continue fileSYS(device + b'[000000]*.SYS') + @level_rule(2) def rule0404(fo, fmt): - """ This presents a major security concern, as other users may potentially -corrupt or delete these files which could render the disk unusable or the -system inoperable.""" + """This presents a major security concern, as other users may potentially + corrupt or delete these files which could render the disk unusable or the + system inoperable.""" if not fmt: print(file=fo) print('Rule 0404', file=fo) print('=========', file=fo) - + def fileSYSProt(root): with FindFile(root) as fi: for fn in fi: # type: ignore fn: bytes - prot = get_security.get_security(fn)[1] + prot = get_security.get_security(fn)[1] if not (prot == 'System: RWED, Owner: RWED, Group: RE, World'): if fmt: print('0404"2"', fn.decode(), file=fo) else: print(fn.decode(), prot.decode(), file=fo) - + devCtx = 0 - devItm = [itemList.itemList (code=dvsdef.DVS__DEVCLASS, value=dcdef.DC__DISK),] - - while(True): + devItm = [ + itemList.itemList(code=dvsdef.DVS__DEVCLASS, value=dcdef.DC__DISK), + ] + + while True: try: - sts,device,devCtx = starlet.device_scan(b'*', devItm, devCtx) + sts, device, devCtx = starlet.device_scan(b'*', devItm, devCtx) except: break - if not lib.getdvi (dvidef.DVI__MNT, device_name=device)[1]: + if not lib.getdvi(dvidef.DVI__MNT, device_name=device)[1]: continue if lib.getdvi(dvidef.DVI__SHDW_MEMBER, device_name=device)[1]: continue fileSYSProt(device + b'[000000]*.SYS') + @level_rule(2) def rule0405(fo, fmt): - """ From a security standpoint, this is extremely dangerous because it -can render the disk unusable or the system inoperable because these files can -be corrupted or deleted by users which have the same identifier granted to -them.""" + """From a security standpoint, this is extremely dangerous because it + can render the disk unusable or the system inoperable because these files can + be corrupted or deleted by users which have the same identifier granted to + them.""" if not fmt: print(file=fo) print('Rule 0405', file=fo) print('=========', file=fo) - + def fileACLrf(fs): - it = (itemList.itemList (code=ossdef.OSS__ACL_LENGTH, dtype=itemList.il_unsignedLong),) - with FindFile (fs) as ifn: + it = ( + itemList.itemList( + code=ossdef.OSS__ACL_LENGTH, dtype=itemList.il_unsignedLong + ), + ) + with FindFile(fs) as ifn: for fn in ifn: # type:ignore fn: bytes - acllen = int (starlet.get_security (objnam=fn, clsnam='FILE',itmlst=it)[2][ossdef.OSS__ACL_LENGTH]) - if (acllen != 0): + acllen = int( + starlet.get_security(objnam=fn, clsnam='FILE', itmlst=it)[ + 2 + ][ossdef.OSS__ACL_LENGTH] + ) + if acllen != 0: if fmt: print('0405"2"', fn.decode(), file=fo) else: print(fn, file=fo) - for e in get_security.get_security (fn)[2]: + for e in get_security.get_security(fn)[2]: if not fmt: - print(' '*9, e.decode(), file=fo) - + print(' ' * 9, e.decode(), file=fo) + for device in DeviceScan(b'*', devclass=dcdef.DC__DISK): - if not (lib.getdvi (dvidef.DVI__MNT, device_name=device)[1]): + if not (lib.getdvi(dvidef.DVI__MNT, device_name=device)[1]): continue - if lib.getdvi (dvidef.DVI__SHDW_MEMBER, device_name=device)[1]: + if lib.getdvi(dvidef.DVI__SHDW_MEMBER, device_name=device)[1]: continue fileACLrf(device + b'[000000]*.SYS') - + + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule0401(fo, len(sys.argv) > 2) rule0403(fo, len(sys.argv) > 2) diff --git a/secrules/rules05.py b/secrules/rules05.py --- a/secrules/rules05.py +++ b/secrules/rules05.py @@ -13,15 +13,17 @@ maxsysgroup = lib.getsyi(syidef.SYI__MAXSYSGROUP)[1] all_users = user.all_users() + def cmp(a, b): return (a > b) - (a < b) + @level_rule(3) def rule0501(fo, fmt): - """ Not having the DISCTLY flag not set allows these accounts to -prematurely abort the system login sequence. This may prevent certain -procedures from being executed during login which may be required for this -site.""" + """Not having the DISCTLY flag not set allows these accounts to + prematurely abort the system login sequence. This may prevent certain + procedures from being executed during login which may be required for this + site.""" if not fmt: print('Rule 0501', file=fo) @@ -34,6 +36,7 @@ else: print(u.username.decode(), file=fo) + @level_rule(3) def rule0502(fo, fmt): """Ensure the DISCTLY flag is set on all accounts.""" @@ -50,12 +53,13 @@ else: print(u.username.decode(), file=fo) + @level_rule(2) def rule0503(fo, fmt): - """ A captive account rarely requires elevated privileges, nor should -it be assigned a system level UIC. In addition, it is recommended that a -user of a captive account not be allowed to change the password for that -account -- The LOCKPWD flag should be set.""" + """A captive account rarely requires elevated privileges, nor should + it be assigned a system level UIC. In addition, it is recommended that a + user of a captive account not be allowed to change the password for that + account -- The LOCKPWD flag should be set.""" if not fmt: print('', file=fo) @@ -63,19 +67,22 @@ print('=========', file=fo) for u in list(all_users.values()): - if (u.flags & uaidef.UAI_M_CAPTIVE): - if (u.flags & uaidef.UAI_M_LOCKPWD) or (u.uic_group <= maxsysgroup): + if u.flags & uaidef.UAI_M_CAPTIVE: + if (u.flags & uaidef.UAI_M_LOCKPWD) or ( + u.uic_group <= maxsysgroup + ): if fmt: print('0503"2"', u.username.decode(), file=fo) else: print(u.username.decode(), u.uic_group, file=fo) + @level_rule(2) def rule0504(fo, fmt): - """ A restricted account rarely requires elevated privileges, nor should -it be assigned a system level UIC. In addition, its PRCLM quota should be -set to zero in order to prevent such a user to spawn out of the restricted -environment.""" + """A restricted account rarely requires elevated privileges, nor should + it be assigned a system level UIC. In addition, its PRCLM quota should be + set to zero in order to prevent such a user to spawn out of the restricted + environment.""" if not fmt: print('', file=fo) @@ -83,19 +90,22 @@ print('=========', file=fo) for u in list(all_users.values()): - if (u.flags & uaidef.UAI_M_CAPTIVE) and ((u.uic_group <= maxsysgroup) or (u.prccnt != 0)): + if (u.flags & uaidef.UAI_M_CAPTIVE) and ( + (u.uic_group <= maxsysgroup) or (u.prccnt != 0) + ): if fmt: print('0504"2"', u.username.decode(), file=fo) else: print(u.username.decode(), u.uic_group, u.prccnt, file=fo) + @level_rule(2) def rule0506(fo, fmt): - """ Unused accounts can present opportunities to penetrate the system. -These accounts have never been utilized on the system. This implies that -these accounts are inactive and, therefore, may be unnecessary. They also -present a potential security risk in that unauthorized users may attempt to -gain access to the system using these accounts.""" + """Unused accounts can present opportunities to penetrate the system. + These accounts have never been utilized on the system. This implies that + these accounts are inactive and, therefore, may be unnecessary. They also + present a potential security risk in that unauthorized users may attempt to + gain access to the system using these accounts.""" if not fmt: print('', file=fo) @@ -103,38 +113,46 @@ print('=========', file=fo) for u in list(all_users.values()): - if (u.lastlogin_i == 0) and (u.lastlogin_n == 0) and not (u.flags & uaidef.UAI_M_DISACNT): + if ( + (u.lastlogin_i == 0) + and (u.lastlogin_n == 0) + and not (u.flags & uaidef.UAI_M_DISACNT) + ): if fmt: print('0506"2"', u.username.decode(), file=fo) else: print(u.username.decode(), file=fo) + @level_rule(2) def rule0507(fo, fmt): - """ Stale accounts can present opportunities to penetrate the system. -These may be stale accounts which are no longer needed. They may also be -utilized as a means to gain unauthorized access to the system.""" + """Stale accounts can present opportunities to penetrate the system. + These may be stale accounts which are no longer needed. They may also be + utilized as a means to gain unauthorized access to the system.""" if not fmt: print('', file=fo) print('Rule 0507', file=fo) print('=========', file=fo) - delta_time = starlet.bintim("90 00:00:00.00")[1] + delta_time = starlet.bintim('90 00:00:00.00')[1] current_time = starlet.bintim(starlet.asctim()[1])[1] limit_time = current_time + delta_time for u in list(all_users.values()): - if ((u.lastlogin_i < limit_time) and (u.lastlogin_n < limit_time )) and not (u.flags & uaidef.UAI_M_DISACNT): + if ( + (u.lastlogin_i < limit_time) and (u.lastlogin_n < limit_time) + ) and not (u.flags & uaidef.UAI_M_DISACNT): if fmt: print('0507"2"', u.username.decode(), file=fo) else: print(u.username.decode(), file=fo) + @level_rule(3) def rule0508(fo, fmt): - """ Improperly defined and maintained user accounts presents opportunities -to penetrate the system, thus giving an unauthorized user access to the system -resources.""" + """Improperly defined and maintained user accounts presents opportunities + to penetrate the system, thus giving an unauthorized user access to the system + resources.""" if not fmt: print('', file=fo) @@ -142,17 +160,18 @@ print('=========', file=fo) for u in list(all_users.values()): - if (u.flags & uaidef.UAI_M_DISACNT): + if u.flags & uaidef.UAI_M_DISACNT: if fmt: print('0508"3"', u.username.decode(), file=fo) else: print(u.username.decode(), file=fo) + @level_rule(3) def rule0509(fo, fmt): - """ Improperly defined and maintained user accounts present opportunities -to penetrate the system, thus giving an unauthorized user access to the system -resources.""" + """Improperly defined and maintained user accounts present opportunities + to penetrate the system, thus giving an unauthorized user access to the system + resources.""" if not fmt: print('', file=fo) @@ -162,34 +181,36 @@ current_time = starlet.bintim(starlet.asctim()[1])[1] for u in list(all_users.values()): - if (0 < u.expiration < current_time): + if 0 < u.expiration < current_time: if fmt: print('0509"3"', u.username.decode(), file=fo) else: print(u.username.decode(), file=fo) + @level_rule(2) def rule0510(fo, fmt): - """ Login related SYGEN parameters define and enforce the login policies -of the site. Improperly defined Login related SYSGEN parameters can result -in the compromise of the operating system environment, and compromise the -confidentiality of customer data.""" + """Login related SYGEN parameters define and enforce the login policies + of the site. Improperly defined Login related SYSGEN parameters can result + in the compromise of the operating system environment, and compromise the + confidentiality of customer data.""" if not fmt: print('', file=fo) print('Rule 0510', file=fo) print('=========', file=fo) - lst = (("LGI_BRK_TERM", syidef.SYI__LGI_BRK_TERM, 0, 0), - ("LGI_BRK_DISUSER", syidef.SYI__LGI_BRK_DISUSER, 0, -1, 1), - ("LGI_PWD_TMO", syidef.SYI__LGI_PWD_TMO, 30, -1, 0), - ("LGI_RETRY_LIM", syidef.SYI__LGI_RETRY_LIM, 3, -1, 0), - ("LGI_RETRY_TMO", syidef.SYI__LGI_RETRY_TMO, 10, 1, 0), - ("LGI_BRK_LIM", syidef.SYI__LGI_BRK_LIM, 3, -1, 0), - ("LGI_BRK_TMO", syidef.SYI__LGI_BRK_TMO, 300, -1, 0), - ("LGI_HID_TIM", syidef.SYI__LGI_HID_TIM, 10, -1, 0), - ("LGI_CALLOUTS", syidef.SYI__LGI_CALLOUTS, 0, 0), - ) + lst = ( + ('LGI_BRK_TERM', syidef.SYI__LGI_BRK_TERM, 0, 0), + ('LGI_BRK_DISUSER', syidef.SYI__LGI_BRK_DISUSER, 0, -1, 1), + ('LGI_PWD_TMO', syidef.SYI__LGI_PWD_TMO, 30, -1, 0), + ('LGI_RETRY_LIM', syidef.SYI__LGI_RETRY_LIM, 3, -1, 0), + ('LGI_RETRY_TMO', syidef.SYI__LGI_RETRY_TMO, 10, 1, 0), + ('LGI_BRK_LIM', syidef.SYI__LGI_BRK_LIM, 3, -1, 0), + ('LGI_BRK_TMO', syidef.SYI__LGI_BRK_TMO, 300, -1, 0), + ('LGI_HID_TIM', syidef.SYI__LGI_HID_TIM, 10, -1, 0), + ('LGI_CALLOUTS', syidef.SYI__LGI_CALLOUTS, 0, 0), + ) for p in lst: r = lib.getsyi(p[1])[1] @@ -198,9 +219,11 @@ print('0510"2"', p[0], file=fo) else: print(p[0], file=fo) - + + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule0501(fo, len(sys.argv) > 2) rule0502(fo, len(sys.argv) > 2) diff --git a/secrules/rules06.py b/secrules/rules06.py --- a/secrules/rules06.py +++ b/secrules/rules06.py @@ -12,12 +12,12 @@ maxsysgroup = lib.getsyi(syidef.SYI__MAXSYSGROUP)[1] - + @level_rule(2) def rule0601(fo, fmt): - """ Improper definition of the network can present opportunities to -penetrate the system. This is a serious security vulnerability since it -allows access from nodes not currently added to the network.""" + """Improper definition of the network can present opportunities to + penetrate the system. This is a serious security vulnerability since it + allows access from nodes not currently added to the network.""" if not fmt: print(file=fo) @@ -29,14 +29,17 @@ if fmt: print('0601"2"', proxy_node, proxy_user, file=fo) else: - print(proxy_node, proxy_user, default_user, local_users, file=fo) + print( + proxy_node, proxy_user, default_user, local_users, file=fo + ) + @level_rule(2) def rule0602(fo, fmt): - """ Improper definition of the network can present opportunities to -penetrate the system. This inconsistency indicates either a potential denial -of service attack, or a potential for unintended access given to a future -user.""" + """Improper definition of the network can present opportunities to + penetrate the system. This inconsistency indicates either a potential denial + of service attack, or a potential for unintended access given to a future + user.""" if not fmt: print(file=fo) @@ -50,21 +53,51 @@ if fmt: print('0602"2"', proxy_node, proxy_user, file=fo) else: - print('1', proxy_node.decode(), proxy_user.decode(), default_user.decode(), file=fo) - print(proxy_node.decode(), proxy_user.decode(), default_user.decode(), local_users_str, file=fo) + print( + '1', + proxy_node.decode(), + proxy_user.decode(), + default_user.decode(), + file=fo, + ) + print( + proxy_node.decode(), + proxy_user.decode(), + default_user.decode(), + local_users_str, + file=fo, + ) for l in local_users: if (l != b'*') and (l != b''): if user_exists(l)[0] is None: if fmt: - print('0602', proxy_node.decode(), proxy_user.decode(), file=fo) + print( + '0602', + proxy_node.decode(), + proxy_user.decode(), + file=fo, + ) else: - print('2', proxy_node.decode(), proxy_user.decode(), l.decode(), file=fo) - print(proxy_node.decode(), proxy_user.decode(), default_user.decode(), local_users_str, file=fo) + print( + '2', + proxy_node.decode(), + proxy_user.decode(), + l.decode(), + file=fo, + ) + print( + proxy_node.decode(), + proxy_user.decode(), + default_user.decode(), + local_users_str, + file=fo, + ) + @level_rule(2) def rule0603(fo, fmt): - """ This is a serious vulnerability because it allows privileged operations -to occur remotely without the user even logging in.""" + """This is a serious vulnerability because it allows privileged operations + to occur remotely without the user even logging in.""" if not fmt: print() @@ -73,25 +106,43 @@ for proxy_node, proxy_user, default_user, local_users in DisplayProxy(): if (default_user != b'*') and (default_user != b''): - g, m = user_exists(default_user) + g, m = user_exists(default_user) if (g is not None) and (g <= maxsysgroup): if fmt: - print('0603"2"', proxy_node.decode(), proxy_user.decode(), file=fo) + print( + '0603"2"', + proxy_node.decode(), + proxy_user.decode(), + file=fo, + ) else: - print(proxy_node.decode(), proxy_user.decode(), default_user.decode(), file=fo) + print( + proxy_node.decode(), + proxy_user.decode(), + default_user.decode(), + file=fo, + ) for l in local_users: if (l != b'*') and (l != b''): - g, m = user_exists(local_users) + g, m = user_exists(local_users) if (g is not None) and (g <= maxsysgroup): if fmt: - print(proxy_node.decode(), proxy_user.decode(), file=fo) + print( + proxy_node.decode(), proxy_user.decode(), file=fo + ) else: - print(proxy_node.decode(), proxy_user.decode(), l.decode(), file=fo) + print( + proxy_node.decode(), + proxy_user.decode(), + l.decode(), + file=fo, + ) + @level_rule(2) def rule0604(fo, fmt): - """ This inconsistency indicates either a potential denial of service -attack, or a potential for unintended enabling of the object in the future.""" + """This inconsistency indicates either a potential denial of service + attack, or a potential for unintended enabling of the object in the future.""" if not fmt: print(file=fo) @@ -108,10 +159,11 @@ else: print(t, u, file=fo) + @level_rule(2) def rule0605(fo, fmt): - """ This is a serious vulnerability because it allows privileged -operations to occur remotely without the user even logging in.""" + """This is a serious vulnerability because it allows privileged + operations to occur remotely without the user even logging in.""" if not fmt: print(file=fo) @@ -122,17 +174,18 @@ r = [x[:-1].split(',') for x in p] for t, u, i in r: - g, m = user_exists(u) + g, m = user_exists(u) if (g is not None) and (g <= maxsysgroup): if fmt: print('0605"2"', t, u, file=fo) else: print(t, u, file=fo) + @level_rule(3) -def rule0606(fo,fmt): - """ Network object executable does not exist. This prevents the network -object from being used.""" +def rule0606(fo, fmt): + """Network object executable does not exist. This prevents the network + object from being used.""" if not fmt: print(file=fo) @@ -148,14 +201,15 @@ print('0606"3"', t, u, i, file=fo) else: print(t, u, i, file=fo) - + + @level_rule(3) def rule0607(fo, fmt): - """ This network object allows remote users to execute remotely any -command procedure they specify, subject to normal access restrictions. It is -more secure to require all procedures that may be remotely executed to be -previously defined in the network object VMS - OpenVMS by eliminating this -object.""" + """This network object allows remote users to execute remotely any + command procedure they specify, subject to normal access restrictions. It is + more secure to require all procedures that may be remotely executed to be + previously defined in the network object VMS - OpenVMS by eliminating this + object.""" if not fmt: print(file=fo) @@ -166,14 +220,16 @@ r = [x[:-1].split(',') for x in p] for t, u, i in r: - if (t == 'TASK'): + if t == 'TASK': if fmt: print('0607"3"', t, u, i, file=fo) else: print(t, u, i, file=fo) + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule0601(fo, len(sys.argv) > 2) rule0602(fo, len(sys.argv) > 2) diff --git a/secrules/rules07.py b/secrules/rules07.py --- a/secrules/rules07.py +++ b/secrules/rules07.py @@ -12,23 +12,26 @@ VMSError = OSError -ids = (('BATCH',0x80000001), - ('DIALUP',0x80000002), - ('INTERACTIVE',0x80000003), - ('LOCAL',0x80000004), - ('NETWORK',0x80000005), - ('REMOTE',0x80000006)) +ids = ( + ('BATCH', 0x80000001), + ('DIALUP', 0x80000002), + ('INTERACTIVE', 0x80000003), + ('LOCAL', 0x80000004), + ('NETWORK', 0x80000005), + ('REMOTE', 0x80000006), +) + @level_rule(2) def rule0701(fo, fmt): - """ The OpenVMS system predefines fixed values for all system identifiers. -If the system identifier values are changed it implies unnecessary tampering -with system resources.""" + """The OpenVMS system predefines fixed values for all system identifiers. + If the system identifier values are changed it implies unnecessary tampering + with system resources.""" if not fmt: print(file=fo) - print("RULE 0701", file=fo) - print("---------", file=fo) + print('RULE 0701', file=fo) + print('---------', file=fo) for n, v in ids: try: @@ -46,40 +49,52 @@ else: print('%s %x' % (n, v), file=fo) + @level_rule(2) def rule0702(fo, fmt): - """ If a user is granted one of these identifiers, it may provide the user -with sufficient privileges to tamper with unauthorized resources on the system -(e.g., critical files, directories, etc.).""" + """If a user is granted one of these identifiers, it may provide the user + with sufficient privileges to tamper with unauthorized resources on the system + (e.g., critical files, directories, etc.).""" if not fmt: print(file=fo) - print("RULE 0702", file=fo) - print("---------", file=fo) + print('RULE 0702', file=fo) + print('---------', file=fo) - id = 0xFFFFFFFF # do a wildcard lookup + id = 0xFFFFFFFF # do a wildcard lookup context = 0 cont = True - while (cont): + while cont: try: s, idn, idv, ida, context = starlet.idtoasc(id, context) - if (idv < 0x80000000): + if idv < 0x80000000: continue - if idn in (b'BATCH', b'DIALUP', b'INTERACTIVE', b'LOCAL', b'REMOTE', - b'NETWORK', b'DECWINDOWS'): + if idn in ( + b'BATCH', + b'DIALUP', + b'INTERACTIVE', + b'LOCAL', + b'REMOTE', + b'NETWORK', + b'DECWINDOWS', + ): continue if idn.split(b'$')[0] in (b'NET', b'SYS', b'SECSRV', b'VMS'): - continue + continue try: s, holder, attrib = starlet.find_holder(idv) except VMSError as e: if e.errno != ssdef.SS__NOSUCHID: raise e - idvs = "%%X%X" % idv + idvs = '%%X%X' % idv if fmt: - print('0702"2"', "id = %s idn = %s" % (idvs, idn.decode()), file=fo) + print( + '0702"2"', + 'id = %s idn = %s' % (idvs, idn.decode()), + file=fo, + ) else: - print("id = %s idn = %s" % (idvs, idn.decode()), file=fo) + print('id = %s idn = %s' % (idvs, idn.decode()), file=fo) except VMSError as e: if e.errno != ssdef.SS__NOSUCHID: raise e @@ -87,143 +102,204 @@ starlet.finish_rdb(context) + @level_rule(2) def rule0703(fo, fmt): - """ This may allow vulnerabilities to exist in these tables making them -susceptible to unwanted changes. The owner of a table can freely add, modify, -and delete entries in the table.""" + """This may allow vulnerabilities to exist in these tables making them + susceptible to unwanted changes. The owner of a table can freely add, modify, + and delete entries in the table.""" if not fmt: print(file=fo) print('RULE 0703', file=fo) print('=========', file=fo) - it = [itemList.itemList(code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong),] + it = [ + itemList.itemList( + code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong + ), + ] - own: int = starlet.get_security(objnam='LNM$SYSTEM_TABLE', clsnam='LOGICAL_NAME_TABLE', - itmlst=it)[2][ossdef.OSS__OWNER] # type: ignore + own: int = starlet.get_security( + objnam='LNM$SYSTEM_TABLE', clsnam='LOGICAL_NAME_TABLE', itmlst=it + )[2][ + ossdef.OSS__OWNER + ] # type: ignore high_word = int(own / 65536) - low_word = int(own - (high_word *65536)) - own_str = "[%o,%o]" % (high_word, low_word) + low_word = int(own - (high_word * 65536)) + own_str = '[%o,%o]' % (high_word, low_word) if own_str != '[1,4]': if fmt: print('0703"2"', own_str, file=fo) else: print(own_str, file=fo) + @level_rule(2) def rule0704(fo, fmt): - """ This allows any user to potentially change these system tables by -removing or adding elements to them. Such actions may allow a user to -circumvent certain system security measures or override safeguards.""" + """This allows any user to potentially change these system tables by + removing or adding elements to them. Such actions may allow a user to + circumvent certain system security measures or override safeguards.""" if not fmt: print(file=fo) print('RULE 0704', file=fo) print('=========', file=fo) - it = [itemList.itemList(code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedLong),] - prot: int = starlet.get_security(objnam='LNM$SYSTEM_TABLE', clsnam='LOGICAL_NAME_TABLE', - itmlst=it)[2][ossdef.OSS__PROTECTION] # type: ignore + it = [ + itemList.itemList( + code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedLong + ), + ] + prot: int = starlet.get_security( + objnam='LNM$SYSTEM_TABLE', clsnam='LOGICAL_NAME_TABLE', itmlst=it + )[2][ + ossdef.OSS__PROTECTION + ] # type: ignore - if not ((prot & 0x8000) and (prot & 0x4000) and (prot & 0x2000)): + if not ((prot & 0x8000) and (prot & 0x4000) and (prot & 0x2000)): if fmt: print('0704"2" LNM$SYSTEM_TABLE', file=fo) else: - print('LNM$SYSTEM_TABLE', lib.format_sogw_prot (prot)[1].decode(), file=fo) + print( + 'LNM$SYSTEM_TABLE', + lib.format_sogw_prot(prot)[1].decode(), + file=fo, + ) + @level_rule(2) def rule0705(fo, fmt): - """ This allows any member of the owners group to potentially change these -system tables by removing or adding elements to them. Such actions may allow -a user to circumvent certain system security measures or override safeguards.""" + """This allows any member of the owners group to potentially change these + system tables by removing or adding elements to them. Such actions may allow + a user to circumvent certain system security measures or override safeguards.""" if not fmt: print(file=fo) print('RULE 0705', file=fo) print('=========', file=fo) - it = [itemList.itemList(code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedLong),] - prot: int = starlet.get_security (objnam='LNM$SYSTEM_TABLE', clsnam='LOGICAL_NAME_TABLE', - itmlst=it)[2][ossdef.OSS__PROTECTION] # type: ignore + it = [ + itemList.itemList( + code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedLong + ), + ] + prot: int = starlet.get_security( + objnam='LNM$SYSTEM_TABLE', clsnam='LOGICAL_NAME_TABLE', itmlst=it + )[2][ + ossdef.OSS__PROTECTION + ] # type: ignore - if not ((prot & 0x800) and (prot & 0x400) and (prot & 0x200)): + if not ((prot & 0x800) and (prot & 0x400) and (prot & 0x200)): if fmt: print('0705"2" LNM$SYSTEM_TABLE', file=fo) else: - print('LNM$SYSTEM_TABLE', lib.format_sogw_prot (prot)[1].decode(), file=fo) + print( + 'LNM$SYSTEM_TABLE', + lib.format_sogw_prot(prot)[1].decode(), + file=fo, + ) + @level_rule(2) def rule0706(fo, fmt): - """ This may allow unauthorized access to users which have the associated -identifiers granted to them.""" + """This may allow unauthorized access to users which have the associated + identifiers granted to them.""" if not fmt: print(file=fo) print('RULE 0706', file=fo) print('=========', file=fo) - it = [itemList.itemList(code=ossdef.OSS__ACL_LENGTH, dtype=itemList.il_unsignedLong),] - acllen:int = starlet.get_security (objnam='LNM$SYSTEM_TABLE', clsnam='LOGICAL_NAME_TABLE', - itmlst=it)[2][ossdef.OSS__ACL_LENGTH] # type:ignore + it = [ + itemList.itemList( + code=ossdef.OSS__ACL_LENGTH, dtype=itemList.il_unsignedLong + ), + ] + acllen: int = starlet.get_security( + objnam='LNM$SYSTEM_TABLE', clsnam='LOGICAL_NAME_TABLE', itmlst=it + )[2][ + ossdef.OSS__ACL_LENGTH + ] # type:ignore - if (acllen != 0): + if acllen != 0: if fmt: print('0706"2" LNM$SYSTEM_TABLE', file=fo) else: - print(get_security.get_security(b'LNM$SYSTEM_TABLE', clsnam=b'LOGICAL_NAME_TABLE'), file=fo) + print( + get_security.get_security( + b'LNM$SYSTEM_TABLE', clsnam=b'LOGICAL_NAME_TABLE' + ), + file=fo, + ) + @level_rule(1) def rule0707(fo, fmt): - """ This could result in unauthorized access to the operating system files, -and compromise system integrity.""" + """This could result in unauthorized access to the operating system files, + and compromise system integrity.""" if not fmt: print(file=fo) print('RULE 0707', file=fo) print('=========', file=fo) - it = [itemList.itemList(code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong),] + it = [ + itemList.itemList( + code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong + ), + ] - ident: int = starlet.get_security (objnam='SYS$SYSDEVICE:', clsnam='DEVICE', - itmlst=it)[2][ossdef.OSS__OWNER] # type: ignore + ident: int = starlet.get_security( + objnam='SYS$SYSDEVICE:', clsnam='DEVICE', itmlst=it + )[2][ + ossdef.OSS__OWNER + ] # type: ignore high_word = int(ident / 65536) - low_word = int(ident - (high_word *65536)) - own = "[%o,%o]" % (high_word, low_word) + low_word = int(ident - (high_word * 65536)) + own = '[%o,%o]' % (high_word, low_word) if (own != '[1,4]') and (own != '[1,1]'): if fmt: print('0707"1" SYS$SYSDEVICE:', file=fo) else: print('SYS$SYSDEVICE:', own, file=fo) + @level_rule(2) def rule0708(fo, fmt): - """ A system shared disk should typically be owned by the SYSTEM account. -A privately mounted disk should be owned by a valid user in the SYSUAF.""" + """A system shared disk should typically be owned by the SYSTEM account. + A privately mounted disk should be owned by a valid user in the SYSUAF.""" if not fmt: print(file=fo) print('RULE 0708', file=fo) print('=========', file=fo) - it = [itemList.itemList(code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong),] + it = [ + itemList.itemList( + code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong + ), + ] - ident: int = starlet.get_security (objnam='SYS$SYSDEVICE:', clsnam='DEVICE', - itmlst=it)[2][ossdef.OSS__OWNER] # type: ignore + ident: int = starlet.get_security( + objnam='SYS$SYSDEVICE:', clsnam='DEVICE', itmlst=it + )[2][ + ossdef.OSS__OWNER + ] # type: ignore high_word = int(ident / 65536) - low_word = int(ident - (high_word *65536)) - own = "[%o,%o]" % (high_word, low_word) + low_word = int(ident - (high_word * 65536)) + own = '[%o,%o]' % (high_word, low_word) try: r = starlet.idtoasc(ident) - g, m =user_exists.user_exists(r[1]) + g, m = user_exists.user_exists(r[1]) if g is None: if fmt: print('0708"2" SYS$SYSDEVICE:', r[1], file=fo) else: - print('SYS$SYSDEVICE:', r[1], own, file=fo) + print('SYS$SYSDEVICE:', r[1], own, file=fo) except VMSError as e: if e == ssdef.SS__NOSUCHID: if fmt: @@ -233,32 +309,45 @@ else: raise e + @level_rule(2) def rule0709(fo, fmt): - """ Incorrect disk protection can yield undesirable access of sensitive -data or files to unauthorized users.""" + """Incorrect disk protection can yield undesirable access of sensitive + data or files to unauthorized users.""" if not fmt: print(file=fo) print('RULE 0709', file=fo) print('=========', file=fo) - it = [itemList.itemList(code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedLong),] + it = [ + itemList.itemList( + code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedLong + ), + ] - prot: int = starlet.get_security (objnam='SYS$SYSDEVICE:', clsnam='DEVICE', - itmlst=it)[2][ossdef.OSS__PROTECTION] # type: ignore + prot: int = starlet.get_security( + objnam='SYS$SYSDEVICE:', clsnam='DEVICE', itmlst=it + )[2][ + ossdef.OSS__PROTECTION + ] # type: ignore if not (prot & 0xFE00): if fmt: print('0709"2" SYS$SYSDEVICE:', file=fo) else: - print('SYS$SYSDEVICE:', lib.format_sogw_prot (prot)[1].decode(), file=fo) + print( + 'SYS$SYSDEVICE:', + lib.format_sogw_prot(prot)[1].decode(), + file=fo, + ) + @level_rule(2) def rule0710(fo, fmt): - """ Highwater marking is a feature of OpenVMS which protects users from -reading files beyond what was written to them. This also is termed disk -scavenging.""" + """Highwater marking is a feature of OpenVMS which protects users from + reading files beyond what was written to them. This also is termed disk + scavenging.""" if not fmt: print(file=fo) @@ -266,22 +355,23 @@ print('=========', file=fo) for device in DeviceScan(b'*', devclass=dcdef.DC__DISK): - if not (lib.getdvi (dvidef.DVI__MNT, device_name=device)[1]): + if not (lib.getdvi(dvidef.DVI__MNT, device_name=device)[1]): continue - if lib.getdvi (dvidef.DVI__SHDW_MEMBER, device_name=device)[1]: + if lib.getdvi(dvidef.DVI__SHDW_MEMBER, device_name=device)[1]: continue - if lib.getdvi (dvidef.DVI__NOHIGHWATER, device_name=device)[1]: + if lib.getdvi(dvidef.DVI__NOHIGHWATER, device_name=device)[1]: if fmt: print('0710"2"', device, file=fo) else: print(device, 'NOHIGHWATER', file=fo) + @level_rule(2) def rule0711(fo, fmt): - """ This feature writes a pattern over the disk space occupied by a file -when the file is deleted. This prevents users from scavenging old data from -the disk which might otherwise be considered reserved only for authorized -users.""" + """This feature writes a pattern over the disk space occupied by a file + when the file is deleted. This prevents users from scavenging old data from + the disk which might otherwise be considered reserved only for authorized + users.""" if not fmt: print(file=fo) @@ -289,68 +379,84 @@ print('=========', file=fo) for device in DeviceScan(b'*', devclass=dcdef.DC__DISK): - if not (lib.getdvi (dvidef.DVI__MNT, device_name=device)[1]): + if not (lib.getdvi(dvidef.DVI__MNT, device_name=device)[1]): continue - if lib.getdvi (dvidef.DVI__SHDW_MEMBER, device_name=device)[1]: + if lib.getdvi(dvidef.DVI__SHDW_MEMBER, device_name=device)[1]: continue - if not lib.getdvi (dvidef.DVI__ERASE_ON_DELETE, device_name=device)[1]: + if not lib.getdvi(dvidef.DVI__ERASE_ON_DELETE, device_name=device)[1]: if fmt: print('0711"2"', device.decode(), file=fo) else: print(device.decode(), 'NO ERASE_ON_DELETE', file=fo) + @level_rule(2) def rule0712(fo, fmt): - """ This allows the owner full access to the volume, which can present a -security risk.""" + """This allows the owner full access to the volume, which can present a + security risk.""" if not fmt: print(file=fo) print('RULE 0712', file=fo) print('=========', file=fo) - it = [itemList.itemList(code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong),] + it = [ + itemList.itemList( + code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong + ), + ] - ident: int = starlet.get_security (objnam='SYS$SYSDEVICE:', clsnam=b'DEVICE', - itmlst=it)[2][ossdef.OSS__OWNER] # type: ignore + ident: int = starlet.get_security( + objnam='SYS$SYSDEVICE:', clsnam=b'DEVICE', itmlst=it + )[2][ + ossdef.OSS__OWNER + ] # type: ignore high_word = int(ident / 65536) - low_word = int(ident - (high_word *65536)) - own = "[%o,%o]" % (high_word, low_word) + low_word = int(ident - (high_word * 65536)) + own = '[%o,%o]' % (high_word, low_word) if (own != '[1,4]') and (own != '[1,1]'): if fmt: print('0712"2" Device SYS$SYSDEVICE:', file=fo) else: - print('Device SYS$SYSDEVICE:', own, file=fo) + print('Device SYS$SYSDEVICE:', own, file=fo) + @level_rule(2) def rule0713(fo, fmt): - """ Owners of a volume should be defined in the SYSUAF. This could -present a security problem, if a user has privileges to define the owner into -the SYSUAF and then login to that account. This would permit the user full -privileges on the volume.""" + """Owners of a volume should be defined in the SYSUAF. This could + present a security problem, if a user has privileges to define the owner into + the SYSUAF and then login to that account. This would permit the user full + privileges on the volume.""" if not fmt: print(file=fo) print('RULE 0713', file=fo) print('=========', file=fo) - it = [itemList.itemList(code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong),] + it = [ + itemList.itemList( + code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong + ), + ] - ident: int = starlet.get_security (objnam='SYS$SYSDEVICE:', clsnam='VOLUME', - itmlst=it)[2][ossdef.OSS__OWNER] # type: ignore + ident: int = starlet.get_security( + objnam='SYS$SYSDEVICE:', clsnam='VOLUME', itmlst=it + )[2][ + ossdef.OSS__OWNER + ] # type: ignore high_word = int(ident / 65536) - low_word = int(ident - (high_word *65536)) - own = "[%o,%o]" % (high_word, low_word) + low_word = int(ident - (high_word * 65536)) + own = '[%o,%o]' % (high_word, low_word) if own != '[1,1]': try: r = starlet.idtoasc(ident) - g, m =user_exists.user_exists(r[1]) + g, m = user_exists.user_exists(r[1]) if g is None: if fmt: print('0713"2" Volume SYS$SYSDEVICE:', file=fo) else: - print('SYS$SYSDEVICE:', r[1].decode(), own, file=fo) + print('SYS$SYSDEVICE:', r[1].decode(), own, file=fo) except VMSError as e: if e == ssdef.SS__NOSUCHID: if fmt: @@ -360,22 +466,34 @@ else: raise e + @level_rule(2) def rule0714(fo, fmt): - """ Incorrect volume protections can prevent users from accessing to the -disks. By default, all users should be granted RWCD access to the volume.""" + """Incorrect volume protections can prevent users from accessing to the + disks. By default, all users should be granted RWCD access to the volume.""" if not fmt: print(file=fo) print('RULE 0714', file=fo) print('=========', file=fo) - it = [itemList.itemList(code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedLong),] + it = [ + itemList.itemList( + code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedLong + ), + ] - prot: int = starlet.get_security (objnam='SYS$SYSDEVICE:', clsnam='VOLUME', - itmlst=it)[2][ossdef.OSS__PROTECTION] # type: ignore + prot: int = starlet.get_security( + objnam='SYS$SYSDEVICE:', clsnam='VOLUME', itmlst=it + )[2][ + ossdef.OSS__PROTECTION + ] # type: ignore accnam = lib.get_accnam('VOLUME')[1] - pvw = lib.format_sogw_prot (prot,access_names=accnam)[1].split(b',')[3].decode() + pvw = ( + lib.format_sogw_prot(prot, access_names=accnam)[1] + .split(b',')[3] + .decode() + ) if pvw[8:] != 'RWCD': if fmt: print('0714"2"SYS$SYSDEVICE:', pvw, file=fo) @@ -385,6 +503,7 @@ if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule0701(fo, len(sys.argv) > 2) rule0702(fo, len(sys.argv) > 2) diff --git a/secrules/rules08.py b/secrules/rules08.py --- a/secrules/rules08.py +++ b/secrules/rules08.py @@ -6,12 +6,13 @@ from ovms import user from ovms import uaidef + @level_rule(1) def rule0801(fo, fmt): - """ This condition allows immediate access to the system to anyone -accessing these accounts. In addition, if any of these accounts is a -privileged account then the system is vulnerable to intentional or -unintentional tampering with critical system resources.""" + """This condition allows immediate access to the system to anyone + accessing these accounts. In addition, if any of these accounts is a + privileged account then the system is vulnerable to intentional or + unintentional tampering with critical system resources.""" if not fmt: print(file=fo) @@ -21,25 +22,26 @@ all_users = user.all_users() for u in list(all_users.values()): - if (u.pwd_length == 0): + if u.pwd_length == 0: du = '' - if (u.flags & uaidef.UAI_M_DISACNT): + if u.flags & uaidef.UAI_M_DISACNT: du = 'DisUser' if fmt: print('0801"1"', u.username.decode(), du, file=fo) else: print(u.username.decode(), u.pwd_length, du, file=fo) + @level_rule(2) def rule0802(fo, fmt): - """ Improper password definition and/or use, such as the use of -predictable and easily guessed passwords, can present opportunities to -penetrate the system. The listed accounts have the DISPWDDIC flag set in -their UAF record. This prevents the system from screening use of a new -password against a system dictionary when the user changes the password for -the account. This allows the same password to be used repetitively for the -account which increases the risk of an unauthorized user guessing the password -and thus gaining access to the system.""" + """Improper password definition and/or use, such as the use of + predictable and easily guessed passwords, can present opportunities to + penetrate the system. The listed accounts have the DISPWDDIC flag set in + their UAF record. This prevents the system from screening use of a new + password against a system dictionary when the user changes the password for + the account. This allows the same password to be used repetitively for the + account which increases the risk of an unauthorized user guessing the password + and thus gaining access to the system.""" if not fmt: print(file=fo) @@ -49,25 +51,26 @@ all_users = user.all_users() for u in list(all_users.values()): - if (u.flags & uaidef.UAI_M_DISPWDDIC): + if u.flags & uaidef.UAI_M_DISPWDDIC: du = '' - if (u.flags & uaidef.UAI_M_DISACNT): + if u.flags & uaidef.UAI_M_DISACNT: du = 'DisUser' if fmt: print('0802"2"', u.username.decode(), du, file=fo) else: print(u.username.decode(), du, file=fo) + @level_rule(2) def rule0803(fo, fmt): - """ Improper password definition and/or use, such as failure to change -passwords on a regular basis, can present opportunities to penetrate the -system. The listed accounts have the DISPWDHIS flag set in their UAF record. -This prevents the system from verifying previous use of a new password when a -user changes the password for the account. This allows the same password to -be used repetitively for the account, which increases the risk of an -unauthorized user guessing the password and thus gaining access to the -system.""" + """Improper password definition and/or use, such as failure to change + passwords on a regular basis, can present opportunities to penetrate the + system. The listed accounts have the DISPWDHIS flag set in their UAF record. + This prevents the system from verifying previous use of a new password when a + user changes the password for the account. This allows the same password to + be used repetitively for the account, which increases the risk of an + unauthorized user guessing the password and thus gaining access to the + system.""" if not fmt: print(file=fo) @@ -77,23 +80,24 @@ all_users = user.all_users() for u in list(all_users.values()): - if (u.flags & uaidef.UAI_M_DISPWDHIS): + if u.flags & uaidef.UAI_M_DISPWDHIS: du = '' - if (u.flags & uaidef.UAI_M_DISACNT): + if u.flags & uaidef.UAI_M_DISACNT: du = 'DisUser' if fmt: print('0803"2"', u.username.decode(), du, file=fo) else: print(u.username.decode(), du, file=fo) + @level_rule(2) def rule0804(fo, fmt): - """ Improper password definition and/or use, such as inadequate password -length and complexity, can present opportunities to penetrate the system. -The listed accounts have an improperly set PWDMINIMUM value, which allows -them to use passwords with lengths which are less than the DISA standard of -6 characters. This increases the risk that the passwords for these accounts -may be guessed thus allowing potential unauthorized access to the system.""" + """Improper password definition and/or use, such as inadequate password + length and complexity, can present opportunities to penetrate the system. + The listed accounts have an improperly set PWDMINIMUM value, which allows + them to use passwords with lengths which are less than the DISA standard of + 6 characters. This increases the risk that the passwords for these accounts + may be guessed thus allowing potential unauthorized access to the system.""" if not fmt: print(file=fo) @@ -103,25 +107,26 @@ all_users = user.all_users() for u in list(all_users.values()): - if (u.pwd_length < 8): + if u.pwd_length < 8: du = '' - if (u.flags & uaidef.UAI_M_DISACNT): + if u.flags & uaidef.UAI_M_DISACNT: du = 'DisUser' if fmt: print('0804"2"', u.username.decode(), du, file=fo) else: print(u.username.decode(), u.pwd_length, du, file=fo) + @level_rule(2) def rule0805(fo, fmt): - """ Improper password definition and/or use, such as failure to change -passwords on a regular basis, can present opportunities to penetrate the -system. An account with no password lifetime restriction may retain its -password indefinitely. This renders the account vulnerable to unauthorized -access if its password is discovered by unauthorized users of that account. -Those accounts with a password lifetime greater than the maximum specified -may also be rendered vulnerable since they are not forced to change their -password within 90 days.""" + """Improper password definition and/or use, such as failure to change + passwords on a regular basis, can present opportunities to penetrate the + system. An account with no password lifetime restriction may retain its + password indefinitely. This renders the account vulnerable to unauthorized + access if its password is discovered by unauthorized users of that account. + Those accounts with a password lifetime greater than the maximum specified + may also be rendered vulnerable since they are not forced to change their + password within 90 days.""" if not fmt: print(file=fo) @@ -133,15 +138,17 @@ for u in list(all_users.values()): if (u.pwd_lifetime > 90) or (u.pwd_lifetime == 0): du = '' - if (u.flags & uaidef.UAI_M_DISACNT): + if u.flags & uaidef.UAI_M_DISACNT: du = 'DisUser' if fmt: print('0805"2"', u.username.decode(), du, file=fo) else: print(u.username.decode(), u.pwd_lifetime, du, file=fo) + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule0801(fo, len(sys.argv) > 2) rule0802(fo, len(sys.argv) > 2) diff --git a/secrules/rules09.py b/secrules/rules09.py --- a/secrules/rules09.py +++ b/secrules/rules09.py @@ -9,41 +9,57 @@ from ovms import ossdef from ovms.rtl.lib.FindFile import FindFile, file_exists + @level_rule(2) def rule0901(fo, fmt): - """ The integrity of VMS startup files is critical to the security and -integrity of the operating environment. Improper access to startup files -can allow unauthorized users to modify their own or another user's execution -environment.""" + """The integrity of VMS startup files is critical to the security and + integrity of the operating environment. Improper access to startup files + can allow unauthorized users to modify their own or another user's execution + environment.""" if not fmt: print(file=fo) print('RULE 0901', file=fo) print('=========', file=fo) - it = [itemList.itemList (code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedWord),] - with FindFile (b'SYS$STARTUP:*.*', b'') as ifn: - for fn in ifn: # type: ignore + it = [ + itemList.itemList( + code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedWord + ), + ] + with FindFile(b'SYS$STARTUP:*.*', b'') as ifn: + for fn in ifn: # type: ignore fn: bytes - prot: int = starlet.get_security (objnam=fn, clsnam='FILE', itmlst=it)[2][ossdef.OSS__PROTECTION] # type: ignore - if not ((prot & 0x8000) and - (prot & 0x4000) and - (prot & 0x2000) and - (prot & 0x1000)): + prot: int = starlet.get_security( + objnam=fn, clsnam='FILE', itmlst=it + )[2][ + ossdef.OSS__PROTECTION + ] # type: ignore + if not ( + (prot & 0x8000) + and (prot & 0x4000) + and (prot & 0x2000) + and (prot & 0x1000) + ): if fmt: print('0901"2"', fn, file=fo) else: print(fn.decode(), file=fo) - print(' ' * 10, lib.format_sogw_prot (prot)[1].decode(), file=fo) + print( + ' ' * 10, + lib.format_sogw_prot(prot)[1].decode(), + file=fo, + ) + @level_rule(3) def rule0902(fo, fmt): - """ During checking of the listed files for non-privileged access, either: -1) An attempt to open the files to check for other called procedures resulted -in an open failure, -OR- 2) The listed command procedures reference other -command procedures which were not found. If a file was required and deleted, -a user could create a file with the same name. This file then would run with -privileged access allowing a user to gain unauthorized system access.""" + """During checking of the listed files for non-privileged access, either: + 1) An attempt to open the files to check for other called procedures resulted + in an open failure, -OR- 2) The listed command procedures reference other + command procedures which were not found. If a file was required and deleted, + a user could create a file with the same name. This file then would run with + privileged access allowing a user to gain unauthorized system access.""" if not fmt: print(file=fo) @@ -59,19 +75,22 @@ print(pi, end=' ', file=fo) pok = not pok + @level_rule(2) def rule0903(fo, fmt): - """ This indicates either a system configuration inconsistency or an -inconsistency in the review criteria.""" + """This indicates either a system configuration inconsistency or an + inconsistency in the review criteria.""" if not fmt: print(file=fo) print('RULE 0903', file=fo) print('=========', file=fo) - lsf = (b'SYS$SYSTEM:STARTUP.COM', - b'SYS$MANAGER:SYSTARTUP_VMS.COM', - b'SYS$SYSTEM:IA64VMSSYS.PAR') + lsf = ( + b'SYS$SYSTEM:STARTUP.COM', + b'SYS$MANAGER:SYSTARTUP_VMS.COM', + b'SYS$SYSTEM:IA64VMSSYS.PAR', + ) for fn in lsf: if not file_exists(fn): @@ -80,8 +99,10 @@ else: print(fn, file=fo) + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule0901(fo, len(sys.argv) > 2) rule0903(fo, len(sys.argv) > 2) diff --git a/secrules/rules10.py b/secrules/rules10.py --- a/secrules/rules10.py +++ b/secrules/rules10.py @@ -4,9 +4,10 @@ from .common import level_rule import os + @level_rule(2) def rule1001(fo, fmt): - """ This prevents accounting history from being recorded.""" + """This prevents accounting history from being recorded.""" if not fmt: print('RULE 1001', file=fo) @@ -24,11 +25,12 @@ print('Accounting is disable', file=fo) break + @level_rule(2) def rule1002(fo, fmt): - """ The related processes and events are not being recorded. If system -level access is not recorded, there is no way to track if an attack is being -made to gain unauthorized access to the system.""" + """The related processes and events are not being recorded. If system + level access is not recorded, there is no way to track if an attack is being + made to gain unauthorized access to the system.""" if not fmt: print('RULE 1002', file=fo) @@ -46,9 +48,10 @@ else: print('LOGIN_FAILURE not accounted', file=fo) + @level_rule(1) def rule1003(fo, fmt): - """ All system security alarms are currently disabled.""" + """All system security alarms are currently disabled.""" if not fmt: print('RULE 1003', file=fo) @@ -64,11 +67,12 @@ print('1003"1" Alarms auditing is disable', file=fo) else: print('Alarms auditing is disable', file=fo) - break + break + @level_rule(2) def rule1004(fo, fmt): - """ Some security alarms are not being reported.""" + """Some security alarms are not being reported.""" if not fmt: print('RULE 1004', file=fo) @@ -93,10 +97,11 @@ else: print('ACL not audited (alarm)', file=fo) + @level_rule(1) def rule1006(fo, fmt): - """ Security alarms are not being reported. Security infractions are not -being recorded.""" + """Security alarms are not being reported. Security infractions are not + being recorded.""" if not fmt: print('RULE 1006', file=fo) @@ -112,11 +117,12 @@ print('1006"1" Report auditing is disable', file=fo) else: print('Report auditing is disable', file=fo) - break + break + @level_rule(2) def rule1007(fo, fmt): - """ Some security infractions are not being recorded.""" + """Some security infractions are not being recorded.""" if not fmt: print('RULE 1007', file=fo) @@ -142,7 +148,10 @@ brk = True if 'Logfailure' in a: lgf_list = a - if 'batch,dialup,local,remote,network,subprocess,detached,server' in a: + if ( + 'batch,dialup,local,remote,network,subprocess,detached,server' + in a + ): lgf = True if not brk: if fmt: @@ -165,8 +174,10 @@ else: print(lgf_list) + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule1001(fo, len(sys.argv) > 2) rule1002(fo, len(sys.argv) > 2) diff --git a/secrules/rules11.py b/secrules/rules11.py --- a/secrules/rules11.py +++ b/secrules/rules11.py @@ -12,10 +12,11 @@ from ovms.rtl.lib.FindFile import file_exists from .getMailObjectInfo import getMailObjectInfo + @level_rule(2) def rule1101(fo, fmt): - """ Many, or all, of their mail files may reside on a different system. -This prevents analysis of the mail files associated with these users.""" + """Many, or all, of their mail files may reside on a different system. + This prevents analysis of the mail files associated with these users.""" if not fmt: print(file=fo) @@ -31,11 +32,12 @@ else: print(e, file=fo) + @level_rule(2) def rule1102(fo, fmt): - """ A users mail file should limit access to the SYSTEM and OWNER -(typically RW for SYSTEM and OWNER and no access for GROUP and WORLD). -The listed files should have their protection changed to (RW,RW,,).""" + """A users mail file should limit access to the SYSTEM and OWNER + (typically RW for SYSTEM and OWNER and no access for GROUP and WORLD). + The listed files should have their protection changed to (RW,RW,,).""" if not fmt: print(file=fo) @@ -44,23 +46,36 @@ all_users = user.all_users() - it = (itemList.itemList (code = ossdef.OSS__PROTECTION, dtype = itemList.il_unsignedWord),) + it = ( + itemList.itemList( + code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedWord + ), + ) for u in list(all_users.values()): df: bytes = u.defdev + u.defdir + b'MAIL.MAI' if file_exists(df): - prot: int = starlet.get_security(objnam=df, clsnam=b'FILE',itmlst=it)[2][ossdef.OSS__PROTECTION] # type: ignore - if (prot != 0xFFCC): + prot: int = starlet.get_security( + objnam=df, clsnam=b'FILE', itmlst=it + )[2][ + ossdef.OSS__PROTECTION + ] # type: ignore + if prot != 0xFFCC: if fmt: print('1102"2"', df.decode(), file=fo) else: print(df.decode(), file=fo) - print(' ' * 10, lib.format_sogw_prot (prot)[1].decode(), file=fo) + print( + ' ' * 10, + lib.format_sogw_prot(prot)[1].decode(), + file=fo, + ) + @level_rule(2) def rule1103(fo, fmt): - """ A users mail file should only be owned by that user. The owner of a -file has full access to the file including read, write and delete privileges -on that file. These files should be changed to specify the proper owner.""" + """A users mail file should only be owned by that user. The owner of a + file has full access to the file including read, write and delete privileges + on that file. These files should be changed to specify the proper owner.""" if not fmt: print(file=fo) @@ -68,28 +83,41 @@ print('=========', file=fo) all_users = user.all_users() - - it = [itemList.itemList (code = ossdef.OSS__OWNER, dtype = itemList.il_unsignedLong),] + + it = [ + itemList.itemList( + code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong + ), + ] for u in list(all_users.values()): - df: bytes = u.defdev+ u.defdir + b'MAIL.MAI' + df: bytes = u.defdev + u.defdir + b'MAIL.MAI' if file_exists(df): - own: int = starlet.get_security (objnam=df, clsnam='FILE',itmlst=it)[2][ossdef.OSS__OWNER] # type: ignore + own: int = starlet.get_security( + objnam=df, clsnam='FILE', itmlst=it + )[2][ + ossdef.OSS__OWNER + ] # type: ignore g = int(own / 65536) - m = int(own - (g *65536)) + m = int(own - (g * 65536)) if (u.uic_group != g) or (u.uic_member != m): if fmt: print('1103"2"', u.username, file=fo) else: - print("%s [%o,%o] %s [%o,%o]" % (df, g, m, u.username, u.uic_group, u.uic_member), file=fo) + print( + '%s [%o,%o] %s [%o,%o]' + % (df, g, m, u.username, u.uic_group, u.uic_member), + file=fo, + ) + @level_rule(3) def rule1104(fo, fmt): - """ During review of the system MAIL object, either 1) The attempt to -gather information on the systems MAIL object was unsuccessful. This implies -that there is no MAIL object available on the system, thus prohibiting the -use of VMS MAIL. -OR- 2) The information collected on the system MAIL object -is incomplete. This implies that the object is not correctly configured or -that the last system upgrade (for openVMS) may have been incomplete.""" + """During review of the system MAIL object, either 1) The attempt to + gather information on the systems MAIL object was unsuccessful. This implies + that there is no MAIL object available on the system, thus prohibiting the + use of VMS MAIL. -OR- 2) The information collected on the system MAIL object + is incomplete. This implies that the object is not correctly configured or + that the last system upgrade (for openVMS) may have been incomplete.""" if not fmt: print(file=fo) @@ -104,9 +132,10 @@ else: print('MAIL object present', file=fo) + @level_rule(4) def rule1105(fo, fmt): - """ This prohibits mail transmissions across the network.""" + """This prohibits mail transmissions across the network.""" if not fmt: print(file=fo) @@ -121,11 +150,12 @@ else: print('Account MAIL$SERVER missing', file=fo) + @level_rule(2) def rule1106(fo, fmt): - """ Not having this flag set allows the account unrestricted access, -which is both unnecessary and undesirable. The RESTRICTED flag should -be set on this account.""" + """Not having this flag set allows the account unrestricted access, + which is both unnecessary and undesirable. The RESTRICTED flag should + be set on this account.""" if not fmt: print(file=fo) @@ -139,12 +169,13 @@ else: print('Account MAIL$SERVER not RESTRICTED', file=fo) + @level_rule(2) def rule1107(fo, fmt): - """ This can permit someone to exploit the privileges of this account, -and presents a risk to the systems overall security. This account should -have its UIC changed to a non-privileged value, i.e. one whose group number -is greater than that specified in the SYSGEN parameter MAXSYSGROUP.""" + """This can permit someone to exploit the privileges of this account, + and presents a risk to the systems overall security. This account should + have its UIC changed to a non-privileged value, i.e. one whose group number + is greater than that specified in the SYSGEN parameter MAXSYSGROUP.""" if not fmt: print(file=fo) @@ -152,18 +183,30 @@ print('=========', file=fo) p, a, u = getMailObjectInfo() - if not a: return + if not a: + return - if u is not None and (u.uic_group <= lib.getsyi(syidef.SYI__MAXSYSGROUP)[1]): + if u is not None and ( + u.uic_group <= lib.getsyi(syidef.SYI__MAXSYSGROUP)[1] + ): if fmt: print('1107"2" Account MAIL$SERVER have System Group', file=fo) else: - print("%s [%o,%o]" % ('Account MAIL$SERVER System Group', u.uic_group, u.uic_member), file=fo) + print( + '%s [%o,%o]' + % ( + 'Account MAIL$SERVER System Group', + u.uic_group, + u.uic_member, + ), + file=fo, + ) + @level_rule(4) def rule1108(fo, fmt): - """ This effectively disables this account for any use. This condition -inhibits mail transmission across the network.""" + """This effectively disables this account for any use. This condition + inhibits mail transmission across the network.""" if not fmt: print(file=fo) @@ -171,7 +214,8 @@ print('=========', file=fo) p, a, u = getMailObjectInfo() - if not a: return + if not a: + return if u is not None and (u.flags & uaidef.UAI_M_DISACNT): if fmt: @@ -179,11 +223,12 @@ else: print('Account MAIL$SERVER is DISUSER', file=fo) + @level_rule(1) def rule1109(fo, fmt): - """ This account should be assigned a password. Not having a password on -this account may grant access to the system via this account from outside -processes, which could exploit this vulnerability.""" + """This account should be assigned a password. Not having a password on + this account may grant access to the system via this account from outside + processes, which could exploit this vulnerability.""" if not fmt: print(file=fo) @@ -191,17 +236,19 @@ print('=========', file=fo) p, a, u = getMailObjectInfo() - if not a: return + if not a: + return if u is not None and (u.pwd_length < 8): if fmt: print('1109"1" Account MAIL$SERVER Password Length', file=fo) else: - print('Account MAIL$SERVER Password Length', u.pwd_length, file=fo) + print('Account MAIL$SERVER Password Length', u.pwd_length, file=fo) + @level_rule(4) def rule1110(fo, fmt): - """ This prohibits mail transmissions across the network.""" + """This prohibits mail transmissions across the network.""" if not fmt: print(file=fo) @@ -209,22 +256,27 @@ print('=========', file=fo) p, a, u = getMailObjectInfo() - if not a: return + if not a: + return - if (u is not None and (u.network_access_p != b'\x00\x00\x00') and - (u.network_access_s != b'\x00\x00\x00')): + if ( + u is not None + and (u.network_access_p != b'\x00\x00\x00') + and (u.network_access_s != b'\x00\x00\x00') + ): if fmt: print('1110"4" MAIL$SERVER no Network Access', file=fo) else: print('Account MAIL$SERVER no Network Access', file=fo) + @level_rule(2) def rule1111(fo, fmt): - """ The mail object account has 1) BATCH, 2) REMOTE, 3) DIALUP, and/or 4) -LOCAL access enabled. This permits respective logins to the system: 1) from -batch jobs submitted by other users which can specify this account as the -user; 2) by a user from a remote node; 3) utilizing a modem; 4) by a local -user. This account should have these accesses disabled.""" + """The mail object account has 1) BATCH, 2) REMOTE, 3) DIALUP, and/or 4) + LOCAL access enabled. This permits respective logins to the system: 1) from + batch jobs submitted by other users which can specify this account as the + user; 2) by a user from a remote node; 3) utilizing a modem; 4) by a local + user. This account should have these accesses disabled.""" if not fmt: print(file=fo) @@ -232,33 +284,44 @@ print('=========', file=fo) p, a, u = getMailObjectInfo() - if not a: return + if not a: + return - if (u is not None and (u.batch_access_p != b'\xff\xff\xff') and - (u.batch_access_s != b'\xff\xff\xff')): - if fmt: - print('1111"2" MAIL$SERVER have REMOTE Access', file=fo) - else: - print('Account MAIL$SERVER have REMOTE Access', file=fo) + if ( + u is not None + and (u.batch_access_p != b'\xff\xff\xff') + and (u.batch_access_s != b'\xff\xff\xff') + ): + if fmt: + print('1111"2" MAIL$SERVER have REMOTE Access', file=fo) + else: + print('Account MAIL$SERVER have REMOTE Access', file=fo) - if (u is not None and (u.remote_access_p != b'\xff\xff\xff') and - (u.remote_access_s != b'\xff\xff\xff')): - if fmt: - print('1111"2" MAIL$SERVER have REMOTE Access', file=fo) - else: - print('Account MAIL$SERVER have REMOTE Access', file=fo) + if ( + u is not None + and (u.remote_access_p != b'\xff\xff\xff') + and (u.remote_access_s != b'\xff\xff\xff') + ): + if fmt: + print('1111"2" MAIL$SERVER have REMOTE Access', file=fo) + else: + print('Account MAIL$SERVER have REMOTE Access', file=fo) - if (u is not None and (u.dialup_access_p != b'\xff\xff\xff') and - (u.dialup_access_s != b'\xff\xff\xff')): - if fmt: - print('1111"2" MAIL$SERVER have DIALUP Access', file=fo) - else: - print('Account MAIL$SERVER have DIALUP Access', file=fo) + if ( + u is not None + and (u.dialup_access_p != b'\xff\xff\xff') + and (u.dialup_access_s != b'\xff\xff\xff') + ): + if fmt: + print('1111"2" MAIL$SERVER have DIALUP Access', file=fo) + else: + print('Account MAIL$SERVER have DIALUP Access', file=fo) + @level_rule(4) def rule1112(fo, fmt): - """ This account requires TMPMBX and NETMBX privileges in order to -function. Lack of these privileges can impede mail transmissions.""" + """This account requires TMPMBX and NETMBX privileges in order to + function. Lack of these privileges can impede mail transmissions.""" if not fmt: print(file=fo) @@ -266,37 +329,53 @@ print('=========', file=fo) p, a, u = getMailObjectInfo() - if not a: return + if not a: + return if u is not None and not (u.priv & prvdef.PRV_M_NETMBX): if fmt: - print('1112"4" Account MAIL$SERVER privilege NETMBX missing', file=fo) + print( + '1112"4" Account MAIL$SERVER privilege NETMBX missing', file=fo + ) else: print('Account MAIL$SERVER privilege NETMBX missing', file=fo) if u is not None and not (u.def_priv & prvdef.PRV_M_NETMBX): if fmt: - print('1112"4" Account MAIL$SERVER default privilege NETMBX missing', file=fo) + print( + '1112"4" Account MAIL$SERVER default privilege NETMBX missing', + file=fo, + ) else: - print('Account MAIL$SERVER default privilege NETMBX missing', file=fo) + print( + 'Account MAIL$SERVER default privilege NETMBX missing', file=fo + ) if u is not None and not (u.priv & prvdef.PRV_M_TMPMBX): if fmt: - print('1112"4" Account MAIL$SERVER privilege TMPMBX missing', file=fo) + print( + '1112"4" Account MAIL$SERVER privilege TMPMBX missing', file=fo + ) else: print('Account MAIL$SERVER privilege TMPMBX missing', file=fo) if u is not None and not (u.def_priv & prvdef.PRV_M_TMPMBX): if fmt: - print('1112"4" Account MAIL$SERVER default privilege TMPMBX missing', file=fo) + print( + '1112"4" Account MAIL$SERVER default privilege TMPMBX missing', + file=fo, + ) else: - print('Account MAIL$SERVER default privilege TMPMBX missing', file=fo) + print( + 'Account MAIL$SERVER default privilege TMPMBX missing', file=fo + ) + @level_rule(2) def rule1113(fo, fmt): - """ If the account contains other weaknesses (such as an ability to access -the system and its resources via this account) then these extra privileges may -allow malicious use of this account to gain unauthorized access to system -objects. This account requires only TMPMBX and NETMBX privileges to function -properly.""" + """If the account contains other weaknesses (such as an ability to access + the system and its resources via this account) then these extra privileges may + allow malicious use of this account to gain unauthorized access to system + objects. This account requires only TMPMBX and NETMBX privileges to function + properly.""" if not fmt: print(file=fo) @@ -304,64 +383,102 @@ print('=========', file=fo) p, a, u = getMailObjectInfo() - if not a: return + if not a: + return msk_prv = prvdef.PRV_M_NETMBX | prvdef.PRV_M_TMPMBX - if u is not None and (u.def_priv ^msk_prv) != 0: + if u is not None and (u.def_priv ^ msk_prv) != 0: if fmt: - print('1113"2" Account MAIL$SERVER excessive default privileges', file=fo) + print( + '1113"2" Account MAIL$SERVER excessive default privileges', + file=fo, + ) else: - print('Account MAIL$SERVER excessive default privileges', file=fo) + print('Account MAIL$SERVER excessive default privileges', file=fo) if u is not None and (u.priv ^ msk_prv) != 0: if fmt: print('1113"2" Account MAIL$SERVER excessive privileges', file=fo) else: print('Account MAIL$SERVER excessive privileges', file=fo) + @level_rule(2) def rule1114(fo, fmt): - """ This may allow this file to be corrupted or deleted by an -unauthorized user.""" + """This may allow this file to be corrupted or deleted by an + unauthorized user.""" if not fmt: print(file=fo) print('RULE 1114', file=fo) print('=========', file=fo) - it = [itemList.itemList (code = ossdef.OSS__OWNER, dtype = itemList.il_unsignedLong),] - - own: int = starlet.get_security (objnam='SYS$SYSTEM:VMSMAIL_PROFILE.DATA', clsnam='FILE',itmlst=it)[2][ossdef.OSS__OWNER] # type: ignore + it = [ + itemList.itemList( + code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong + ), + ] + + own: int = starlet.get_security( + objnam='SYS$SYSTEM:VMSMAIL_PROFILE.DATA', clsnam='FILE', itmlst=it + )[2][ + ossdef.OSS__OWNER + ] # type: ignore g = int(own / 65536) - m = int(own - (g *65536)) + m = int(own - (g * 65536)) if (g != 1) or (m != 4): if fmt: print('1114"2" SYS$SYSTEM:VMSMAIL_PROFILE.DATA bad owner', file=fo) else: - print("%s [%o,%o]" % ('SYS$SYSTEM:VMSMAIL_PROFILE.DATA bad owner', g, m,), file=fo) - + print( + '%s [%o,%o]' + % ( + 'SYS$SYSTEM:VMSMAIL_PROFILE.DATA bad owner', + g, + m, + ), + file=fo, + ) + + @level_rule(2) def rule1115(fo, fmt): - """ This may allow this file to be corrupted or deleted by unauthorized -users.""" + """This may allow this file to be corrupted or deleted by unauthorized + users.""" if not fmt: print(file=fo) print('RULE 1115', file=fo) print('=========', file=fo) - it = (itemList.itemList (code = ossdef.OSS__PROTECTION, dtype = itemList.il_unsignedWord),) - prot: int = starlet.get_security (objnam='SYS$SYSTEM:VMSMAIL_PROFILE.DATA', clsnam='FILE',itmlst=it)[2][ossdef.OSS__PROTECTION] # type: ignore + it = ( + itemList.itemList( + code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedWord + ), + ) + prot: int = starlet.get_security( + objnam='SYS$SYSTEM:VMSMAIL_PROFILE.DATA', clsnam='FILE', itmlst=it + )[2][ + ossdef.OSS__PROTECTION + ] # type: ignore - if (prot != 0xFF88): + if prot != 0xFF88: if fmt: - print('1115"2" SYS$SYSTEM:VMSMAIL_PROFILE.DATA bad protection', file=fo) + print( + '1115"2" SYS$SYSTEM:VMSMAIL_PROFILE.DATA bad protection', + file=fo, + ) else: - print('SYS$SYSTEM:VMSMAIL_PROFILE.DATA', lib.format_sogw_prot (prot)[1].decode(), file=fo) - + print( + 'SYS$SYSTEM:VMSMAIL_PROFILE.DATA', + lib.format_sogw_prot(prot)[1].decode(), + file=fo, + ) + + @level_rule(2) def rule1116(fo, fmt): - """ This will prevent the mail system from functioning. It also may -indicate tampering with the operational environment.""" + """This will prevent the mail system from functioning. It also may + indicate tampering with the operational environment.""" if not fmt: print(file=fo) @@ -374,8 +491,10 @@ else: print('SYS$SYSTEM:MAIL_SERVER.EXE not exists', file=fo) + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule1101(fo, len(sys.argv) > 2) rule1102(fo, len(sys.argv) > 2) diff --git a/secrules/rules12.py b/secrules/rules12.py --- a/secrules/rules12.py +++ b/secrules/rules12.py @@ -8,60 +8,65 @@ accname = lib.get_accnam('QUEUE')[1] + @level_rule(2) def rule1201(fo, fmt): - """ This allows the owner control over the queue and could lead to loss, or restriction, of service from this queue. -By default, the printer and batch queues should be owned by the SYSTEM account.""" + """This allows the owner control over the queue and could lead to loss, or restriction, of service from this queue. + By default, the printer and batch queues should be owned by the SYSTEM account.""" if not fmt: print('RULE 1201', file=fo) print('=========', file=fo) for q in queues.all_queues(): - nam = q.queue_name - own: int = q.owner_uic # type: ignore + nam = q.queue_name + own: int = q.owner_uic # type: ignore g = int(own / 65536) - m = int(own - (g *65536)) + m = int(own - (g * 65536)) if (g != 1) or (m != 4): if fmt: print('1201"2"', nam.decode(), file=fo) else: - print("%s [%o,%o]" % (nam.decode(), g, m), file=fo) + print('%s [%o,%o]' % (nam.decode(), g, m), file=fo) + @level_rule(2) def rule1202(fo, fmt): - """ This can lead to undesired or unauthorized manipulation of the queue such that service may be interrupted or -compromised. Queues should retain their default protection values as specified when initialized.""" + """This can lead to undesired or unauthorized manipulation of the queue such that service may be interrupted or + compromised. Queues should retain their default protection values as specified when initialized.""" if not fmt: print('RULE 1202', file=fo) print('=========', file=fo) for q in queues.all_queues(): - nam = q.queue_name - prot: int = q.protection # type: ignore - if (prot != 0xDE7B): + nam = q.queue_name + prot: int = q.protection # type: ignore + if prot != 0xDE7B: if fmt: print('1202"2"', nam, file=fo) else: prt = lib.format_sogw_prot(prot, access_names=accname)[1] print(nam, prt.decode(), file=fo) + @level_rule(3) def rule1203(fo, fmt): - """ This denies print/batch service to users via these queues.""" + """This denies print/batch service to users via these queues.""" if not fmt: print('RULE 1203', file=fo) print('=========', file=fo) for q in queues.all_queues(): - nam: bytes = q.queue_name + nam: bytes = q.queue_name qsts = q.queue_status - if (qsts & quidef.QUI_M_QUEUE_STOPPED): + if qsts & quidef.QUI_M_QUEUE_STOPPED: if fmt: print('1203"3"', nam.decode(), file=fo) else: print(nam.decode(), 'Stopped', file=fo) + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule1201(fo, len(sys.argv) > 2) rule1202(fo, len(sys.argv) > 2) diff --git a/secrules/rules13.py b/secrules/rules13.py --- a/secrules/rules13.py +++ b/secrules/rules13.py @@ -11,21 +11,23 @@ VMSError = OSError + def path_exists(fn): try: - with FindFile (fn, b'') as ifn: + with FindFile(fn, b'') as ifn: ifn.__next__() return 1 except StopIteration as e: - return 3 + return 3 except VMSError as e: return 2 + @level_rule(3) def rule1301(fo, fmt): - """ This condition precludes performing requested security checks for these users. Either their home directories need -to be added to the system, or the users may need to be removed from the SYSUAF if these are accounts which have expired and/or -are no longer in use.""" + """This condition precludes performing requested security checks for these users. Either their home directories need + to be added to the system, or the users may need to be removed from the SYSUAF if these are accounts which have expired and/or + are no longer in use.""" if not fmt: print('RULE 1301', file=fo) @@ -37,61 +39,84 @@ print('skip default account', file=fo) continue fn: bytes = u.defdev + u.defdir + b'*.*' - if (path_exists(fn) == 2): + if path_exists(fn) == 2: if fmt: print('1301"3"', fn.decode(), file=fo) else: print(fn.decode(), 'not exists', u.username.decode(), file=fo) + @level_rule(2) def rule1303(fo, fmt): - """ This makes these files potentially vulnerable to access, modification, or deletion by unauthorized users. The methods -of access may be available via an ACL on the file, the files UIC protection, and/or user access via the directory path or user -privileges. If GROUP is displayed, then there are non-privileged users in the same group as the file owner, which have the -listed accesses to the file.""" + """This makes these files potentially vulnerable to access, modification, or deletion by unauthorized users. The methods + of access may be available via an ACL on the file, the files UIC protection, and/or user access via the directory path or user + privileges. If GROUP is displayed, then there are non-privileged users in the same group as the file owner, which have the + listed accesses to the file.""" if not fmt: print('RULE 1303', file=fo) print('=========', file=fo) all_users = user.all_users() - it = (itemList.itemList (code = ossdef.OSS__PROTECTION, dtype = itemList.il_unsignedWord),) + it = ( + itemList.itemList( + code=ossdef.OSS__PROTECTION, dtype=itemList.il_unsignedWord + ), + ) for u in list(all_users.values()): fn = u.defdev + u.defdir + b'*.*' - if (path_exists(fn)== 1): - sep = (u.defdev+u.defdir)[-1:] - arbo = (u.defdev+u.defdir)[:-1] + b'...' + sep + b'*.*' - with FindFile(arbo, b'')as ifn: - for f in ifn: # type: ignore + if path_exists(fn) == 1: + sep = (u.defdev + u.defdir)[-1:] + arbo = (u.defdev + u.defdir)[:-1] + b'...' + sep + b'*.*' + with FindFile(arbo, b'') as ifn: + for f in ifn: # type: ignore f: bytes try: - retsec = starlet.get_security(objnam=f, clsnam='FILE',itmlst=it) - prot: int = retsec[2][ossdef.OSS__PROTECTION] # type: ignore - if ((prot & 0x8000) or - (prot & 0x4000) or - (prot & 0x2000) or - (prot & 0x1000) or - (prot & 0x800) or - (prot & 0x400) or - (prot & 0x200) or - (prot & 0x100)): - if fmt: - print('1303"2"', f, file=fo) - else: - print(f.decode(), file=fo) - print(' ' * 10, lib.format_sogw_prot (prot)[1].decode(), file=fo) + retsec = starlet.get_security( + objnam=f, clsnam='FILE', itmlst=it + ) + prot: int = retsec[2][ + ossdef.OSS__PROTECTION + ] # type: ignore + if ( + (prot & 0x8000) + or (prot & 0x4000) + or (prot & 0x2000) + or (prot & 0x1000) + or (prot & 0x800) + or (prot & 0x400) + or (prot & 0x200) + or (prot & 0x100) + ): + if fmt: + print('1303"2"', f, file=fo) + else: + print(f.decode(), file=fo) + print( + ' ' * 10, + lib.format_sogw_prot(prot)[1].decode(), + file=fo, + ) except VMSError as e: - if e.errno not in (rmsdef.RMS__FNF, ssdef.SS__NOSUCHFILE): + if e.errno not in ( + rmsdef.RMS__FNF, + ssdef.SS__NOSUCHFILE, + ): raise + @level_rule(2) def rule1304(fo, fmt): - """ Improper ownership may prevent these users from accessing their directories, and may allow the owner full reign on -the files in the directory, and possibly all files in the directory tree.""" + """Improper ownership may prevent these users from accessing their directories, and may allow the owner full reign on + the files in the directory, and possibly all files in the directory tree.""" if not fmt: print('RULE 1304', file=fo) print('=========', file=fo) - it = [itemList.itemList (code = ossdef.OSS__OWNER, dtype = itemList.il_unsignedLong),] + it = [ + itemList.itemList( + code=ossdef.OSS__OWNER, dtype=itemList.il_unsignedLong + ), + ] all_users = user.all_users() for u in list(all_users.values()): fn: bytes = u.defdev + u.defdir @@ -100,7 +125,11 @@ fu = fn + b'.-]' + d + b'.DIR' if not file_exists(fu): continue - own: int = starlet.get_security(objnam=fu, clsnam='FILE', itmlst=it)[2][ossdef.OSS__OWNER] # type:ignore + own: int = starlet.get_security(objnam=fu, clsnam='FILE', itmlst=it)[ + 2 + ][ + ossdef.OSS__OWNER + ] # type:ignore high = int(own / 65536) low = int(own - high * 65536) if high != u.uic_group or low != u.uic_member: @@ -110,33 +139,38 @@ else: print(mark, u.username.decode(), file=fo) + @level_rule(3) def rule1310(fo, fmt): - """ This could prevent the user accounts from functioning properly. It could indicate a denial of service situation.""" + """This could prevent the user accounts from functioning properly. It could indicate a denial of service situation.""" if not fmt: print('RULE 1310', file=fo) print('=========', file=fo) all_users = user.all_users() for u in list(all_users.values()): - df = u.defdev + u.defdir + b'*.*' - lgicmd:bytes = b'' + df = u.defdev + u.defdir + b'*.*' + lgicmd: bytes = b'' try: - with FindFile (u.lgicmd if u.lgicmd != b'' else b'LOGIN.COM', df) as fi: - for f in fi: # type: ignore + with FindFile( + u.lgicmd if u.lgicmd != b'' else b'LOGIN.COM', df + ) as fi: + for f in fi: # type: ignore f: bytes lgicmd = f - break + break except VMSError as e: - continue + continue if lgicmd == b'' or not file_exists(lgicmd): if fmt: - print('1310"3"', u.username.decode(), file=fo) + print('1310"3"', u.username.decode(), file=fo) else: print(u.username.decode(), lgicmd.decode(), file=fo) + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule1301(fo, len(sys.argv) > 2) rule1303(fo, len(sys.argv) > 2) diff --git a/secrules/rules14.py b/secrules/rules14.py --- a/secrules/rules14.py +++ b/secrules/rules14.py @@ -6,6 +6,7 @@ __version__ = '1.0' + @level_rule(2) def rule1401(fo, fmt): if not fmt: @@ -22,10 +23,10 @@ instr = False state = 0 for l in r: - if (l == ''): + if l == '': continue if l[0] != ' ': - dspec = l.replace('.000000','') + dspec = l.replace('.000000', '') fspec = None elif ';' in l: priv = auth = None @@ -45,18 +46,24 @@ priv = l elif 'Authorized = ' in l: auth = l - with FindFile.FindFile(fspec.encode(), dspec.encode()) as fi: #type: ignore - for f in fi: # type: ignore + with FindFile.FindFile( + fspec.encode(), dspec.encode() + ) as fi: # type: ignore + for f in fi: # type: ignore f: bytes if hasPriv: if fmt: print('1401"2"', f.decode(), file=fo) else: print(f.decode(), file=fo) - if priv: print(priv, file=fo) - if auth: print(auth, file=fo) + if priv: + print(priv, file=fo) + if auth: + print(auth, file=fo) + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule1401(fo, len(sys.argv) > 2) diff --git a/secrules/rules15.py b/secrules/rules15.py --- a/secrules/rules15.py +++ b/secrules/rules15.py @@ -6,6 +6,7 @@ __version__ = '1.0' + @level_rule(1) def rule1501(fo, fmt): if not fmt: @@ -16,22 +17,24 @@ r = [x[:-1].rstrip() for x in p] for l in r: - if (l == ''): + if l == '': continue if l[:7] == 'Service': continue s = l.split() - if s[0] in 'FINGER,FTP,RLOGIN,SNMP,TELNET,REXEC,RSH': - if s[5]=='0.0.0.0': + if s[0] in 'FINGER,FTP,RLOGIN,SNMP,TELNET,REXEC,RSH': + if s[5] == '0.0.0.0': v = '%s %s' % (s[0], s[6]) - else: + else: v = '%s %s' % (s[0], s[5]) if fmt: print('1501"1"', v, file=fo) else: print(v, file=fo) + if __name__ == '__main__': import sys + fo = open(sys.argv[1], 'w') if len(sys.argv) > 1 else sys.stdout rule1501(fo, len(sys.argv) > 2) diff --git a/secrules/user_exists.py b/secrules/user_exists.py --- a/secrules/user_exists.py +++ b/secrules/user_exists.py @@ -1,10 +1,15 @@ from ovms import starlet from ovms import itemList, uaidef + def user_exists(u): - itm = (itemList.itemList (code=uaidef.UAI__UIC, dtype=itemList.il_unsignedLong),) + itm = ( + itemList.itemList( + code=uaidef.UAI__UIC, dtype=itemList.il_unsignedLong + ), + ) try: - s, ctxt, uic = starlet.getuai (usrnam=u, itmlst=itm) + s, ctxt, uic = starlet.getuai(usrnam=u, itmlst=itm) uic_g = list(uic.values())[0] / 65536 uic_m = list(uic.values())[0] - (uic_g * 65536) return uic_g, uic_m diff --git a/securityrules.py b/securityrules.py --- a/securityrules.py +++ b/securityrules.py @@ -15,7 +15,7 @@ debugpy.configure(subProcess=False) debugpy.listen(('0.0.0.0', 5678), in_process_debug_adapter=True) - print("Waiting for debugger attach") + print('Waiting for debugger attach') debugpy.wait_for_client() debugpy.breakpoint() print('break on this line') @@ -24,6 +24,7 @@ all_rules = {} args = None + def rules_exec(seclass, numrule=None, info=False, fo=None, export=None): global all_rules, args rules = all_rules[seclass][1] @@ -47,10 +48,11 @@ else: getattr(m, rname)(fo, export) + class InflateRange(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): lst = [] - for string in values: # type: ignore + for string in values: # type: ignore string = string.replace('(', '') string = string.replace(')', '') if '-' in string or ':' in string: @@ -58,31 +60,41 @@ m = re.match(r'(\d+)(?:-(\d+))?$', string) # ^ (or use .split('-'). anyway you like.) if not m: - raise argparse.ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + raise argparse.ArgumentTypeError( + "'" + + string + + "' is not a range of number. Expected forms like '0-5' or '2'." + ) start = m.group(1) end = m.group(2) or start - lst.extend(list(range(int(start,10), int(end,10)+1))) + lst.extend(list(range(int(start, 10), int(end, 10) + 1))) else: - string = string.replace(',', ' ') - for string in string.split(' '): - if string: - lst.append(int(string)) + string = string.replace(',', ' ') + for string in string.split(' '): + if string: + lst.append(int(string)) setattr(namespace, self.dest, lst) + def load_rules(levels): global all_rules - mods = [fn[:-3] for fn in os.listdir('./secrules') - if fn.startswith('rule') and fn[-1:].lower() == 'y'] + mods = [ + fn[:-3] + for fn in os.listdir('./secrules') + if fn.startswith('rule') and fn[-1:].lower() == 'y' + ] all_rules = {} for modn in mods: m = importlib.import_module('.' + modn, 'secrules') # m = __import__('secrules.' + modn, globals(), locals(), ['*'], -1) - lst = [m,[]] + lst = [m, []] for r in dir(m): if r.startswith('rule'): - if (levels is None or - not hasattr(getattr(m, r), 'rule_level') or - getattr(m, r).rule_level in levels): + if ( + levels is None + or not hasattr(getattr(m, r), 'rule_level') + or getattr(m, r).rule_level in levels + ): lst[1].append(r) all_rules[modn] = lst # all_rules[modn] = (m, [r for r in dir(m) if r.startswith('rule')]) @@ -91,15 +103,45 @@ def main(): global args parser = argparse.ArgumentParser(description='security checker') - parser.add_argument('--output', type=argparse.FileType('w'), dest='fo', - metavar='out-file', help='output file', default=sys.stdout) - parser.add_argument('--class', type=int, dest='seclass', help='security class') - parser.add_argument('--rule', action=InflateRange, nargs='*', dest='numrule', help='rule number') - parser.add_argument('--export', action='store_true', dest='export', - default=False, help='export format') - parser.add_argument('--info', action='store_true', dest='info', - default=False, help='Rules info') - parser.add_argument('--level', action=InflateRange, nargs='*', dest='levels', help='rule levels') + parser.add_argument( + '--output', + type=argparse.FileType('w'), + dest='fo', + metavar='out-file', + help='output file', + default=sys.stdout, + ) + parser.add_argument( + '--class', type=int, dest='seclass', help='security class' + ) + parser.add_argument( + '--rule', + action=InflateRange, + nargs='*', + dest='numrule', + help='rule number', + ) + parser.add_argument( + '--export', + action='store_true', + dest='export', + default=False, + help='export format', + ) + parser.add_argument( + '--info', + action='store_true', + dest='info', + default=False, + help='Rules info', + ) + parser.add_argument( + '--level', + action=InflateRange, + nargs='*', + dest='levels', + help='rule levels', + ) args = parser.parse_args() @@ -107,15 +149,16 @@ if args.seclass is None: if args.numrule is not None: - raise argparse.ArgumentTypeError("missing seclass argument") + raise argparse.ArgumentTypeError('missing seclass argument') lst = list(all_rules.keys()) lst.sort() for seclass in lst: -# seclass = 'rules%02d' % args.seclass + # seclass = 'rules%02d' % args.seclass rules_exec(seclass, args.numrule, args.info, args.fo, args.export) else: seclass = 'rules%02d' % args.seclass rules_exec(seclass, args.numrule, args.info, args.fo, args.export) + if __name__ == '__main__': main()