def _check_shadow(self): # check passwords have been changed in the pass # TODO do this automatically cmd = "for usr in $(cut -d: -f1 /etc/shadow); do [[ $(chage --list $usr | grep '^Last password change' | cut -d: -f2) > $(date) ]] && echo \"$usr :$(chage --list $usr | grep '^Last password change' | cut -d: -f2)\"; done" output = common.run_full(cmd) if output != "": common.reminder("Ensure these are all in the past:\n" + str(output))
def _set_password_lockout(self): paths = ["/etc/pam.d/system-authand", "/etc/pam.d/password-auth"] for path in paths: if os.path.isfile(path): common.warn( "{} exists, needs checking (password lockout)".format( path)) path = "/etc/pam.d/common-auth" common.backup(path) with open(path) as in_file: lines = in_file.read().split("\n") permit_index = None # used for fedora based distros # text = """auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900 # auth required pam_faillock.so preauth audit silent deny=5 unlock_time=900 # auth sufficient pam_unix.so # auth [default=die] pam_faillock.so authfail audit deny=5unlock_time=900 # auth sufficient pam_faillock.so authsucc audit deny=5 unlock_time=900""" text = """auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900""" for index, line in enumerate(lines): if "pam_faillock.so" in line: common.warn( "Found faillock, needs checking (password lockout)") elif "pam_permit.so" in line: permit_index = index if text == lines[permit_index - 1]: common.debug("Tally already exists") elif permit_index is not None: lines.insert(permit_index, text) else: common.error("Error {} not formatted as expected".format(path)) return with open(path, "w") as out_file: out_file.write("\n".join(lines)) # Ensure user doesn't get locked out user = common.input_text("Enter current user") common.run("pam_tally2 -u {} --reset".format(user)) # Everytime they use sudo the tally gets reset with open("/home/{}/.bashrc".format(user), "a") as out_file: out_file.write( "\nalias sudo='sudo pam_tally2 -u {} --reset >/dev/null; sudo '\n" .format(user)) common.reminder( "You need to reload .bashrc in all currently used terminals: source ~/.bashrc" ) common.debug("Set Password Lockout")
def _configure_hosts(self): """Secure allow and deny hosts files.""" common.backup("/etc/hosts.allow") common.backup("/etc/hosts.deny") reminder = "You need to set up /etc/hosts.allow\nIn the format: 'ALL: <net>/<mask>, <net>/<mask>'" common.reminder(reminder) with open("/etc/hosts.deny", "w") as out_file: out_file.write("ALL: ALL") common.set_permissions("/etc/hosts.allow", "root", "root", "644") common.set_permissions("/etc/hosts.deny", "root", "root", "644")
def execute(self): """Sets Permissions on Important Files.""" common.set_permissions("/etc/passwd", "root", "root", "644") common.set_permissions("/etc/shadow", "root", "shadow", "o-rwx,g-wx") common.set_permissions("/etc/group", "root", "root", "644") common.set_permissions("/etc/gshadow", "root", "shadow", "o-rwx,g-rw") common.set_permissions("/etc/passwd-", "root", "root", "u-x,go-wx") common.set_permissions("/etc/shadow-", "root", "root", "o-rwx,g-rw") common.set_permissions("/etc/group-", "root", "root", "u-x,go-wx") common.set_permissions("/etc/gshadow-", "root", "root", "o-rwx,g-rw") reminder = "Check there are no rouge programs:\n" + common.run_full( "df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -4000" ) common.reminder(reminder)
def execute(self): """Secures Banners.""" self._write_file("/etc/motd", "CADS CyberCenturion\n") self._write_file( "/etc/issue", "Authorized uses only. All activity may be monitored and reported.\n" ) self._write_file( "/etc/issue.net", "Authorized uses only. All activity may be monitored and reported.\n" ) common.set_permissions("/etc/motd", "root", "root", "644") common.set_permissions("/etc/issue", "root", "root", "644") common.set_permissions("/etc/issue.net", "root", "root", "644") common.reminder( "Check if GDM is installed, and if so configure banners correctly")
def run(plugins=[]): """Runs the plugins. Args: plugins (list[str], optional): An option list of specific plugins to run """ all_plugins = plugin.Plugin._registry failures = [] # Sort plugins in priority order all_plugins.sort(key=lambda x: x.priority) for p in all_plugins: if plugin_slug(p) in plugins: debug("Plugin: {} (targets {} version {}, priority {})".format( p.name, p.os, p.os_version, p.priority)) if plugin.os_check(p.os, p.os_version): instance = p() info("Running {}...".format(p.name)) try: instance.execute() except Exception as ex: reminder("The plugin {} failed to run".format(p.name), ex) failures.append(plugin_slug(p)) else: warn("Not running {} as this is not the right OS".format( p.name)) else: warn("Skipping {}".format(p.name)) reminder( "To run all of the failed plugins again, execute CentSecure with the following argument: '-r {}'" .format(" ".join(failures)))
def _remove_interfaces(self): """Remove Wireless Interfaces.""" interfaces = common.run("iwconfig", ignore_error=True) if interfaces: reminder = "Please disable any wifi interfaces\nip link set <interface> down" + interfaces common.reminder(reminder)
def execute(self): """Execute plugin.""" reminder = "Make sure Firefox has been updated to the latest version (70+) in order for the settting to apply\nFirefox will have to be restarted" common.reminder(reminder) self._add_user_js()
def _set_password_requirements( self ): # also deals with password reuse and ensuring sha512 is used # /etc/pam.d/system-auth - check if exists due to alternative method of implementation path = "/etc/pam.d/system-auth" if os.path.isfile(path): common.reminder( "{} exists, needs checking (cracklib/pwquality)".format(path)) path = "/etc/pam.d/common-password" common.backup(path) # we need to ensure cracklib is installed, it will also change common-password common.run("sudo apt install libpam-cracklib -y -q") common.backup(path) with open(path) as in_file: lines = in_file.read().split("\n") cracklib_index = None pwquality_index = None unix_index = None for index, line in enumerate(lines): if "pam_cracklib.so" in line: cracklib_index = index elif "pam_pwquality.so" in line: pwquality_index = index elif "pam_unix.so" in line: unix_index = index cracklib = "password required pam_cracklib.so try_first_pass retry=3 minlen=14 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1" pwquality = "password requisite pam_pwquality.so try_first_pass retry=3" # we can also ensure that it remembers passwords unix = "password sufficient pam_unix.so sha512 shadow use_authtok remember=5" if unix_index is not None: lines[unix_index] = unix else: common.error( "Error, could not find unix_index, {} is misconfigured".format( path)) return # You can use either cracklib or pwquality, but one of them must be used if cracklib_index is not None: lines[cracklib_index] = cracklib elif pwquality_index is not None: common.debug("pwquality is used instead of cracklib") lines[pwquality_index] = pwquality else: # no cracklib or pwquality, we'll add cracklib (in the right place) common.error("Cracklib is not configured correctly") return with open(path, "w") as out_file: out_file.write("\n".join(lines)) # This only needs to be done for the pwquality, although it can't hurt to do it anyway path = "/etc/security/pwquality.conf" common.backup(path) with open(path, "w") as out_file: text = "minlen = 14\ndcredit = -1\nucredit = -1\nocredit = -1\nlcredit = -1" out_file.write(text) common.info("Added Password requirements")