Пример #1
0
def rkhunter(EMAIL):

    # Rootkit Detection With Rkhunter
    f_rkhunter_conf = '/etc/rkhunter.conf'
    if not General.answer('Do you want to install and configure rkhunter?'):
        return

    General.run_cmd('apt install rkhunter -y')
    General.error_message(
        '[ALERT] If this is the first installation select yes to the three questions you will be asked to answer '
    )
    time.sleep(5)
    General.output_message('Configuring rkhunter..')
    General.change_lines(
        f_rkhunter_conf,
        _1=['UPDATE_MIRRORS=0', 'UPDATE_MIRRORS=1\n'],
        _2=['MIRRORS_MODE=1', 'MIRRORS_MODE=0\n'],
        _3=['#MAIL-ON-WARNING=root', f'MAIL-ON-WARNING={EMAIL}\n'],
        _4=['#COPY_LOG_ON_ERROR=0', 'COPY_LOG_ON_ERROR=1\n'],
        _5=['#PKGMGR=NONE', 'PKGMGR=DPKG\n'],
        _6=['#PHALANX2_DIRTEST=0', 'PHALANX2_DIRTEST=1\n'],
        _7=['#USE_LOCKING=0', 'USE_LOCKING=1\n'],
        _8=[
            '#SHOW_SUMMARY_WARNINGS_NUMBER=0',
            'SHOW_SUMMARY_WARNINGS_NUMBER=1\n'
        ],
        _9=['WEB_CMD="/bin/false"', 'WEB_CMD=""\n'])
    subprocess.check_call(['dpkg-reconfigure', 'rkhunter'],
                          stderr=subprocess.STDOUT)
    General.run_cmd('rkhunter --propupd', 'rkhunter --update')
    General.output_message('Rkhunter Done')
Пример #2
0
def proc():
    # Securing /proc | /proc mounted with hidepid=2 so users can only see information about their processes
    error = 'Fatal Error: PROC will have to be configured manually'
    f_ntp_conf = "/etc/ntp.conf"
    response = General.answer('Securing /proc so users can only see information about their processes?')


    if not response: return
    General.output_message('Configuring proc')

    if not os.path.exists(f_ntp_conf):
        General.error_message(f"could not localte the file {f_ntp_conf}. Exiting /proc configuration.")
        return

    with open(f_ntp_conf, 'a') as file:
        file.write(f'''
       # added by debian9_Hardening.py on {datetime.today().strftime('%Y-%m-%d')} @ {datetime.now().strftime(
            '%H:%M:%S')}       
       proc     /proc     proc     defaults,hidepid=2     0     0
               ''')
Пример #3
0
def ntp():
    # installing NTP client and keeping server time in-sync

    error = 'Fatal Error: NTP will have to be configured manually'
    response = General.answer(
        'Install NTP client and keeping server time in-sinc ?')
    check_attempt = 0
    f_ntp_conf = '/etc/ntp.conf'
    if not response: return

    General.run_cmd('apt install ntp -y')

    if not os.path.exists(f_ntp_conf):
        General.error_message(
            f"could not localte the file {f_ntp_conf}. Exiting ntp configuration."
        )
        return

    General.output_message('Configuring NTP')
    with open(f_ntp_conf, 'w') as file:
        file.write(f'''
    # added by debian9_Hardening.py on {datetime.today().strftime('%Y-%m-%d')} @ {datetime.now().strftime('%H:%M:%S')}        
    driftfile /var/lib/ntp/ntp.drift
    statistics loopstats peerstats clockstats
    filegen loopstats file loopstats type day enable
    filegen peerstats file peerstats type day enable
    filegen clockstats file clockstats type day enable
    restrict -4 default kod notrap nomodify nopeer noquery limited
    restrict -6 default kod notrap nomodify nopeer noquery limited
    restrict 127.0.0.1
    restrict ::1
    restrict source notrap nomodify noquery
    pool pool.ntp.org iburst
            ''')

    General.run_cmd('service ntp restart')
Пример #4
0
def lynis():

    if not General.answer(
            'Do you want install Lynis for upgrade your security level?'):
        return

    General.run_cmd('git clone https://github.com/CISOfy/lynis /opt/lynis')
    General.output_message('Lynis installed in > /opt/lynis')
    General.output_message('Running lynis scan..')
    output = str(
        subprocess.check_output(['./lynis', 'audit', 'system', '-Q'],
                                cwd="/opt/lynis",
                                stderr=subprocess.STDOUT), 'utf-8')
    General.output_message('Scan completed')
    output = General.remove_ansi_escape(output)
    lynis_output_sections = dict()
    output = output.split('[+]')

    for section in output:
        if ('------------------------------------') in section:
            section = section.split('------------------------------------')
            if section[0].strip() == 'Plugins (phase 2)':
                section[1] = section[1].split(
                    '================================================================================'
                )
                lynis_output_sections[
                    section[0].strip()] = section[1][0].strip()
                section[1][1] = section[1][1].split('Suggestions')
                section[1][1][1] = section[1][1][1].split(
                    '----------------------------')
                lynis_output_sections['Suggestions'] = section[1][1][1][1]
            else:
                lynis_output_sections[section[0].strip()] = section[1].strip()

    if ('Kernel Hardening' in lynis_output_sections):
        section = lynis_output_sections['Kernel Hardening']

        section = section.split('-')
        for line in section:
            line = line.strip()
            if '[ DIFFERENT ]' in line:
                line = line.split()
                for word in line:
                    if ')' in word:
                        word = word.strip('()exp: ')
                        if len(word) == 1:
                            word = word[0]
                        elif len(word) == 2:
                            word = word[1]
                        elif len(word) == 3:
                            word = word[2]
                        print(f'sysctl -w {line[0].strip()}={word}')
                        General.run_cmd(f'sysctl -w {line[0].strip()}={word}')

    print('\n\n\n')
    if ('Suggestions' in lynis_output_sections):
        suggestions = lynis_output_sections['Suggestions'].split('*')
        suggestions_list = []
        for suggestion in suggestions:
            suggestion = suggestion.split('\n')
            suggestions_list.append(suggestion[0].strip())

        if 'Protect rescue.service by using sulogin [BOOT-5260]' in suggestions_list:
            task = 'BOOT-5260'
            General.output_message(f'Configuring {task}')
            with open('/usr/lib/systemd/system/rescue.service', 'r') as file:
                lines = file.readlines()
                for index, line in enumerate(lines):
                    if 'ExecStart' in line.strip().split('='):
                        lines[index] = 'ExecStart=-/usr/sbin/sulogin'

            with open('/usr/lib/systemd/system/rescue.service', 'w') as f_w:

                for line in lines:
                    f_w.write(line)
            General.output_message(f'{task}')

        if 'Determine priority for available kernel update [KRNL-5788]' in suggestions_list:

            # https://phoenixnap.com/kb/how-to-update-kernel-ubuntu

            task = 'KRNL-5788'
            General.output_message(f'Configuring {task}')
            General.run_cmd('apt-get update')
            General.output_message('System updated')
            General.run_cmd('apt-get dist-upgrade')

        if 'Configure minimum password age in /etc/login.defs [AUTH-9286]' in suggestions_list or\
                'Configure maximum password age in /etc/login.defs [AUTH-9286]' in suggestions_list or \
                'Default umask in /etc/login.defs could be more strict like 027 [AUTH-9328]' in suggestions_list:
            task = 'AUTH-9286'
            General.change_lines(
                '/etc/login.defs',
                _1=['UMASK		022', 'UMASK		027\n'],
                _2=['PASS_MAX_DAYS	99999', 'PASS_MAX_DAYS   30\n'],
                _3=['PASS_MIN_DAYS	0', 'PASS_MIN_DAYS   1\n'],
                _4=['PASS_WARN_AGE   7', 'PASS_WARN_AGE   7\n'],
            )
            General.output_message(f'Configuring {task}')
        else:
            General.error_message(
                'Something went wrong, cannot analize lynis scan output')
Пример #5
0
def clamAv(EMAIL):
    # Anti-Virus Scanning With ClamAV

    f_clam_conf = '/etc/clamav/freshclam.conf'

    if not General.answer('Do you want to use ClamAV for Anti-virus Scanning with root permissions?'): return

    General.run_cmd('apt install clamav clamav-freshclam -y')
    General.change_lines(
        f_clam_conf,
        _1=[
            '# Check for new database 24 times a day',
            '# Check for new database 1 times a day\n'
        ],
        _2=[
            'Checks 24',
            'Checks 1\n'
        ]
    )
    General.run_cmd('freshclam -v')




    user = ''
    while True:
        user = General.input_message(
            "Using clamscan as root is dangerous because if a file is in fact a virus there is risk that it could use the root privileges.\n"
            "You can create another user by writing [U] \nPlease chose a user that can run clamscan"
        )
        if UsersConfig.user_exists(user): break
        if user.upper() == 'U':
            UsersConfig.create_users()
        else:
            General.error_message("User doesn't exists")
            General.output_message('For create a new user type [U]')


    dir_to_scan = ''
    all_directories_exists = False
    while not all_directories_exists:
        all_directories_exists = True
        dir_to_scan = General.input_message('Which direcotry should be scanned by clamAV? (ex. /var/www /var/vmail): ')
        for dir in dir_to_scan.split():
            if not os.path.exists(dir):
                General.error_message(f"The directory {dir} doesn't exists, select another path")
                all_directories_exists = False
    General.output_message('Configuration Anti-virus Scanning tools..')

    f_clam_daily = f'/home/{user}/clamscan_daily.sh'

    with open(f_clam_daily, 'w') as file:
        file.write(f'''
    #!/bin/bash
    LOGFILE="/var/log/clamav/clamav-$(date +'%Y-%m-%d').log";
    EMAIL_MSG="Please see the log file attached.";
    EMAIL_FROM="''' + EMAIL + '''";
    DIRTOSCAN="''' + dir_to_scan + '''";

    for S in ${DIRTOSCAN}; do
     DIRSIZE=$(du -sh "$S" 2>/dev/null | cut -f1);

     echo "Starting a daily scan of "$S" directory.
     Amount of data to be scanned is "$DIRSIZE".";

     clamscan -ri "$S" >> "$LOGFILE";

     # get the value of "Infected lines"
     MALWARE=$(tail "$LOGFILE"|grep Infected|cut -d" " -f3);

     # if the value is not equal to zero, send an email with the log file attached
     if [ "$MALWARE" -ne "0" ];then
     # using heirloom-mailx below
     echo "$EMAIL_MSG"|mail -A "$LOGFILE" -s "Malware Found" "$EMAIL_FROM";
    fi 
    done

    exit 0
                    ''')

    General.run_cmd('chmod 0755 /root/clamscan_daily.sh')
    General.run_cmd('ln /root/clamscan_daily.sh /etc/cron.daily/clamscan_daily')
    General.run_cmd('service clamav-freshclam start')
    if not General.answer("Do you want to run the virus scan on the given directories now? This can take some time"): return
    General.output_message('Running first scan for check if all is ok')
    subprocess.run(['clamscan', '-r', dir_to_scan])
Пример #6
0
sys.path.insert(
    0, os.path.abspath(__file__ +
                       "/../../"))  # add the current module to sys.path

from SSLock import General, UsersConfig, Mail, SSHConfig, Nvidia, Ntp, Proc, EntropyPool, Ufw, Fail2Ban, Aide, ClamAv, Maldet, \
    RkHunter, Logwatch, Audit, Psad, Alerts, Lynis, WordpresServerSetup, WPVirtualHostSetup

if General.internet_on(): print("Internet connection active")
# Installing non present packages

# Checking if script runs as root
General.output_message('Script is running as root?...')
if os.geteuid() != 0:
    General.error_message(
        "You need to have root privileges to run this script.\nRe-run the script using 'sudo'. Exiting..."
    )
    exit()

General.output_message('YES')

# Store global informations
EMAIL_ENABLE = General.answer(
    "To receive notifications from the system and for the correct configuration of some tools, email and Exim4 will"
    " be used ok? \n[if your system is already configured to send mail, you don't have to follow this step] "
)

if EMAIL_ENABLE:
    EMAIL = General.input_message("Email")
else:
    EMAIL = General.input_message(
Пример #7
0
def ssh(SSH_ENABLE, EMAIL_ENABLE, SSH_PORT, EMAIL):

    f_ssh_config = '/etc/ssh/sshd_config'
    if not SSH_ENABLE or not EMAIL_ENABLE: return
    General.run_cmd("apt install ssh -y")
    options_list = [
        'Port', 'ClientAliveCountMax', 'ClientAliveInterval', 'LoginGraceTime',
        'MaxAuthTries', 'MaxSessions', 'MaxStartups', 'PasswordAuthentication',
        'AllowGroups', 'PermitRootLogin'
    ]

    for option in options_list:
        status1 = General.check_lines_in_file(f_ssh_config, option)
        status2 = General.check_lines_in_file(f_ssh_config, '#' + option)
        if not status1 and not status2:
            with open(f_ssh_config, 'a') as file:
                file.write(option + '\n')

    generate_key = General.answer('Do you want enable ssh for some users?')
    if generate_key:
        generate_root_key = General.answer(
            f'Do you also want to enable ssh for Current user [{General.USER}] ? '
        )
        if generate_root_key:
            key_path = f'/{General.USER}/.ssh/id_rsa'
            if not os.path.exists(key_path):
                key_pass = General.input_message(
                    'Enter a passphrase for the key (empty for no passphrase):'
                )
                General.run_cmd(
                    f'ssh-keygen -C "{EMAIL}" -b 2048 -t rsa -f {key_path} -q -N "{key_pass}"'
                )
                General.warning_message(
                    f'[ALERT] your private key has been sent by email to {EMAIL}, please retrieve and save it, after destroy the email\n'
                )
                time.sleep(3)
                General.run_cmd(
                    f'echo " DANGER here you will find your private key attached for your device, destroy this mail and its contents instantly." | mail -s "Private key for: {General.USER} on {General.HOSTNAME}" {EMAIL} -A {key_path}'
                )
            else:
                General.error_message(
                    'A key pair for the current user yet exists')
        else:
            General.change_lines(
                f_ssh_config,
                _19=['#PermitRootLogin yes', 'PermitRootLogin no\n'],
                _20=['PermitRootLogin yes', 'PermitRootLogin no\n'])

        General.run_cmd('groupadd sshusers')
        General.output_message("which user do you want to have ssh enabled?")
        while True:
            user = General.input_message("User to enable ssh  [S to skip]: ")
            if user.upper() in ['S', 'SKIP']: break

            if not UsersConfig.user_exists(user):
                General.error_message("User doesn't exists")
            else:
                General.run_cmd(f'usermod -a -G sshusers {user}')
                generate_key_for_user = General.answer(
                    f'[{user}] Do you want a ssh key pair for this user?')
                if generate_key_for_user:
                    key_path = f'/home/{user}/.ssh/id_rsa'
                    if not os.path.exists(f'/home/{user}/.ssh'):
                        os.mkdir(f'/home/{user}/.ssh')
                    if not os.path.exists(key_path):
                        key_pass = General.input_message(
                            'Enter a passphrase for the key (empty for no passphrase):'
                        )
                        General.run_cmd(
                            f'ssh-keygen -C "{EMAIL}" -b 2048 -t rsa -f {key_path} -q -N "{key_pass}"'
                        )
                        General.warning_message(
                            f'[ALERT] your private key has been sent by email to {EMAIL}, please retrieve and save it, after destroy the email\n'
                        )
                        time.sleep(3)
                        General.run_cmd(
                            f'echo " DANGER here you will find your private key attached for your device, destroy this mail and its contents instantly." | mail -s "Private key for: {user} on {General.HOSTNAME}" {EMAIL} -A {key_path}'
                        )
                    else:
                        General.error_message(
                            f'A key pair for the user "{user}" yet exists')

        General.change_lines(
            f_ssh_config,
            _1=['Port', f"Port {SSH_PORT}\n"],
            _2=['#Port', f"Port {SSH_PORT}\n"],
            _3=['ClientAliveCountMax', "ClientAliveCountMax 0\n"],
            _4=['#ClientAliveCountMax', "ClientAliveCountMax 0\n"],
            _5=['ClientAliveInterval', "ClientAliveInterval 300\n"],
            _6=['#ClientAliveInterval', "ClientAliveInterval 300\n"],
            _7=['LoginGraceTime', "LoginGraceTime 30\n"],
            _8=['#LoginGraceTime', "LoginGraceTime 30\n"],
            _9=['MaxAuthTries', "MaxAuthTries 2\n"],
            _10=['#MaxAuthTries', "MaxAuthTries 2\n"],
            _11=['MaxSessions', "MaxSessions 2\n"],
            _12=['#MaxSessions', "MaxSessions 2\n"],
            _13=['MaxStartups', "MaxStartups 2\n"],
            _14=['#MaxStartups', "MaxStartups 2\n"],
            _15=['PasswordAuthentication', "PasswordAuthentication no\n"],
            _16=['#PasswordAuthentication', "PasswordAuthentication no\n"],
            _17=['AllowGroups', "AllowGroups sshusers\n"],
            _18=['#AllowGroups', "AllowGroups sshusers\n"],
        )

        General.output_message('These changes have been made to the config')
        General.warning_message('/etc/ssh/sshd_config')
        General.output_message(
            f'''If u need more advanced options feel free to modify it.
    - Port                      {SSH_PORT};
    - ClientAliveCountMax                0;
    - ClientAliveInterval              300;
    - LoginGraceTime                    30;
    - MaxAuthTries                       2;
    - MaxSessions                        2;
    - MaxStartups                        2;
    - PasswordAuthentication            no;
    - AllowGroups                 sshusers;
    - PermitRootLogin                   no;
''')

        General.output_message(
            'removing all Diffie-Hellman keys that are less than 3072 bits long'
        )
        General.run_cmd(
            "awk '$5 >= 3071' /etc/ssh/moduli | sudo tee /etc/ssh/moduli.tmp")
        General.run_cmd('mv /etc/ssh/moduli.tmp /etc/ssh/moduli')

        response = General.answer('do you want to enable 2FA/MFA for SSH?')
        if response:
            General.warning_message(
                'Note: a user will only need to enter their 2FA/MFA code if they are logging on with their password but not if they are using SSH public/private keys.\n'
            )
            General.run_cmd('apt install libpam-google-authenticator -y')
            General.warning_message(
                '\n[ALERT]  Notice this can not run as root, at the next machine restart RUN "google-authenticator"\n'
            )
            time.sleep(5)
            General.output_message(
                'Select default option (y in most cases) for all the questions it asks and remember to save the emergency scratch codes.'
            )
            time.sleep(2)
            General.run_cmd(
                'echo -e "\nauth       required     pam_google_authenticator.so nullok         # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | tee -a /etc/pam.d/sshd'
            )