def entropy_pool(): # More Secure Random Entropy Pool (WIP) response = General.answer('Do you want More Secure Random Entropy Pool (WIP)?') check_attempt = 0 if not response: return General.run_cmd('apt install rng-tools -y') General.run_cmd('echo "HRNGDEVICE=/dev/urandom" >> /etc/default/rng-tools') General.run_cmd('systemctl start rng-tools')
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 ''')
def auditd(EMAIL): f_audit_rules = '/etc/audit/audit.rules' f_audit_report = '/etc/cron.d/audit-report' if not General.answer('Do you want to install and configure auditd?'): return General.run_cmd('apt install auditd -y') General.output_message('Configuring Audit') General.run_cmd( f'wget -q https://raw.githubusercontent.com/Neo23x0/auditd/master/audit.rules -O {f_audit_rules}' ) General.run_cmd('systemctl restart auditd') with open(f_audit_report, 'w') as file: file.write(f''' MAILTO={EMAIL} 1 0 * * * root /sbin/aureport -k -ts yesterday 00:00:00 -te yesterday 23:59:59 ''')
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')
def logwatch(EMAIL): # logwatch - system log analyzer and reporter f_logwatch = '/etc/cron.daily/00logwatch' if not General.answer('Do you want to install and configure logwatch?'): return General.run_cmd('apt install logwatch -y') with open(f_logwatch, 'w') as file: file.write(f''' #!/bin/bash #Check if removed-but-not-purged test -x /usr/share/logwatch/scripts/logwatch.pl || exit 0 #execute /usr/sbin/logwatch --output mail --format html --mailto {EMAIL} --range yesterday --service all ''') General.warning_message( 'Restarting firewall Maybe existing ssh connections will be stopped\n') General.run_cmd('ufw --force enable')
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')
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')
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])
def aide(EMAIL): # File/Folder Integrity Monitoring With AID f_aide = '/etc/default/aide' if not main.answer('Do you want Monitoring File/Folder Integrity With AIDE?'): return main.run_cmd('apt install aide -y') main.output_message('Configuration File/Folder Monitoring tools..') main.change_lines( f_aide, _1=[ 'MAILTO=root', f'MAILTO={EMAIL}\n' ], _2=[ '#CRON_DAILY_RUN=yes', 'CRON_DAILY_RUN=yes\n' ] ) main.output_message( "Aide, for work, needs to create a new database and install it" "\nThis process requires time..." ) main.run_cmd_interactive("aideinit -y -f") main.run_cmd("cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db") main.run_cmd("update-aide.conf") main.run_cmd("cp /var/lib/aide/aide.conf.autogenerated /etc/aide/aide.conf")
- SSH KEYS SETUP ( not covered in the script ) : https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys-on-ubuntu-20-04 - ADDING USERS """ import sys import os import traceback 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"
def autamated_email_allerts(EMAIL_ENABLE, EMAIL): f_exm_conf = '/etc/exim4/update-exim4.conf.conf' file_path_1 = '/etc/exim4/passwd.client' f_exim_localmacros = '/etc/exim4/exim4.conf.localmacros' f_exim_template = '/etc/exim4/exim4.conf.template' f_exim_autogenerated = '/var/lib/exim4/config.autogenerated' # if not EMAIL_ENABLE: return General.run_cmd('apt install exim4 openssl ca-certificates -y') General.output_message('Editing configuration files..') General.run_cmd('chown root:Debian-exim /etc/exim4/passwd.client') General.run_cmd('chown 640 /etc/exim4/passwd.client') if not os.path.exists('/usr/share/doc/exim4-base/examples/exim-gencert'): General.run_cmd('bash /usr/share/doc/exim4-base/examples/exim-gencert') with open(f_exim_localmacros, 'w') as file: file.write(''' MAIN_TLS_ENABLE = 1 REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = * TLS_ON_CONNECT_PORTS = 465 REQUIRE_PROTOCOL = smtps IGNORE_SMTP_LINE_LENGTH_LIMIT = true ''') General.run_cmd(f'wget -q https://raw.githubusercontent.com/TheeBlind/Exim4_Gmail_conf/master/nconf/config.autogenerated -O {f_exim_autogenerated}') General.run_cmd(f'wget -q https://raw.githubusercontent.com/TheeBlind/Exim4_Gmail_conf/master/nconf/exim4.conf.template -O {f_exim_template}') General.run_cmd(f'wget -q https://raw.githubusercontent.com/TheeBlind/Exim4_Gmail_conf/master/nconf/update-exim4.conf.conf -O {f_exm_conf}') local_ip = subprocess.check_output(['hostname', '-I'], stderr=subprocess.STDOUT) local_ip = str(local_ip).strip("b'n\\ ") General.change_lines(f_exim_template, _1=[ '* changeme Ffrs', f"* {local_ip}@{General.USER}.{General.HOSTNAME} Ffrs\n" ]) General.change_lines( f_exim_autogenerated, _1=[ '* chengeme Ffrs', f"* {local_ip}@{General.USER}.{General.HOSTNAME} Ffrs\n" ]) General.run_cmd('update-exim4.conf') General.run_cmd('systemctl restart exim4') General.run_cmd(f"""echo "Automatic SSlock notification test, if you received this mail, you can go ahead in the setup. if you have received this mail by mistake, please delete it." | mail -s 'Test!' {EMAIL}""") General.output_message('Mail setup Completed') response = General.answer(f'We have sent a test mail to the address {EMAIL}. Have you recived it?\nCheck the spam folder!') if not response: General.output_message( """ If you received no mail you can check the exim4 logs for investigate about the problem > sudo cat /var/log/exim4/mainlog > sudo cat /var/log/exim4/paniclog > check if something is blocking port 25 out """) time.sleep(5)
def fail2ban(EMAIL): # Application Intrusion Detection And Prevention With Fail2Ban f_f2b_jail = '/etc/fail2ban/jail.local' if not General.answer('Do you want to install and configure Fail2Ban?'): return General.run_cmd('apt install fail2ban -y') General.run_cmd('systemctl start fail2ban', 'systemctl enable fail2ban') General.output_message("fail2ban is running") with open(f_f2b_jail, 'w') as file: lan_segment = General.input_message( 'What is you lan segment? (ex. 192.168.1.1/24) :') file.write(f''' [DEFAULT] # the IP address range we want to ignore ignoreip = 127.0.0.1/8 {lan_segment} # who to send e-mail to destemail = {EMAIL} # who is the email from sender = {General.USER}.{General.HOSTNAME}.{EMAIL} # since we're using exim4 to send emails mta = mail # get email alerts action = %(action_mwl)s ''') General.output_message('Configuring Intrusion and detection tools') if not General.answer( 'Do You need a jail for SSH that tells fail2ban to look at SSH logs and use ufw to ban/unban IPs ?' ): return with open(f_f2b_jail, 'a') as jail_file: jail_file.write(''' [sshd] enabled = true banaction = ufw port = ssh filter = sshd logpath = %(sshd_log)s maxretry = 5 ''') General.run_cmd('fail2ban-client start', 'fail2ban-client reload') General.output_message("Tools reloaded") General.run_cmd('systemctl restart fail2ban')
def alerts(EMAIL): # Automatic Security Updates and Alerts f_alerts_upgrades = '/etc/apt/apt.conf.d/51myunattended-upgrades' f_alerts_conf = '/etc/apticron/apticron.conf' if not General.answer( 'Do you want Automatic Security Updates and Alerts? (unattended-upgrades)' ): return General.run_cmd( 'apt install unattended-upgrades apt-listchanges apticron -y') General.output_message('Configuring Security Updates and Alerts..') with open(f_alerts_upgrades, 'w') as file: file.write(''' // Enable the update/upgrade script (0=disable) APT::Periodic::Enable "1"; // Do "apt-get update" automatically every n-days (0=disable) APT::Periodic::Update-Package-Lists "1"; // Do "apt-get upgrade --download-only" every n-days (0=disable) APT::Periodic::Download-Upgradeable-Packages "1"; // Do "apt-get autoclean" every n-days (0=disable) APT::Periodic::AutocleanInterval "7"; // Send report mail to root // 0: no report (or null string) // 1: progress report (actually any string) // 2: + command outputs (remove -qq, remove 2>/dev/null, add -d) // 3: + trace on APT::Periodic::Verbose "2"; APT::Periodic::Unattended-Upgrade "1"; // Automatically upgrade packages from these Unattended-Upgrade::Origins-Pattern { "o=Debian,a=stable"; "o=Debian,a=stable-updates"; "origin=Debian,codename=${distro_codename},label=Debian-Security"; }; // You can specify your own packages to NOT automatically upgrade here Unattended-Upgrade::Package-Blacklist { }; // Run dpkg --force-confold --configure -a if a unclean dpkg state is detected to true to ensure that updates get installed even when the system got interrupted during a previous run Unattended-Upgrade::AutoFixInterruptedDpkg "true"; //Perform the upgrade when the machine is running because we wont be shutting our server down often Unattended-Upgrade::InstallOnShutdown "false"; // Send an email to this address with information about the packages upgraded. Unattended-Upgrade::Mail "''' + EMAIL + '''"; // Always send an e-mail Unattended-Upgrade::MailOnlyOnError "false"; // Remove all unused dependencies after the upgrade has finished Unattended-Upgrade::Remove-Unused-Dependencies "true"; // Remove any new unused dependencies after the upgrade has finished Unattended-Upgrade::Remove-New-Unused-Dependencies "true"; // Automatically reboot WITHOUT CONFIRMATION if the file /var/run/reboot-required is found after the upgrade. Unattended-Upgrade::Automatic-Reboot "true"; // Automatically reboot even if users are logged in. Unattended-Upgrade::Automatic-Reboot-WithUsers "true"; ''') with open(f_alerts_conf, 'w') as file: file.write(f''' EMAIL="{EMAIL}" NOTIFY_NO_UPDATES="1" ''')
def wpVirtualHost(EMAIL): #################################################### # SETUP APACHE VIRTUALHOST ( FOR MULTIPLE WEBSITES ) #################################################### General.output_message("-- Creation of apache2 Virtual Host --") DOMAIN_FULL = General.input_message("Insert a domain[ domain.(com/.it/.org/etc..) ] ") DOMAIN = '.'.join(DOMAIN_FULL.split(".")[:-1]) if len(DOMAIN_FULL.split(".")) > 2 else DOMAIN_FULL.split(".")[0] General.run_cmd(f"mkdir /var/www/{DOMAIN}") # create a directory for the virtual host General.run_cmd(f"chown -R $USER:$USER /var/www/{DOMAIN}") # assign the directory to $USER General.run_cmd(f"chmod -R 755 /var/www/{DOMAIN}") # be sure that permissions are correct f_apache_domain_conf = f'/etc/apache2/sites-available/{DOMAIN}.conf' with open(f_apache_domain_conf, 'w') as file: file.write( """ <VirtualHost *:80> ServerAdmin """ + EMAIL + """ ServerName """ + DOMAIN_FULL + """ ServerAlias www.""" + DOMAIN_FULL + """ DocumentRoot /var/www/""" + DOMAIN + """ ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> <Directory /var/www/""" + DOMAIN + """/> AllowOverride All </Directory> """) General.run_cmd(f"sudo a2ensite {DOMAIN}.conf") # Enable the new configuration ( you can enable as many different configs as you want ) General.run_cmd(f"sudo a2dissite 000-default.conf") # Disable the default configuration General.run_cmd("sudo a2enmod rewrite") General.run_cmd("sudo systemctl restart apache2") # restart apache # Test apache configs # sudo apachectl -t -D DUMP_VHOSTS # sudo apachectl configtest # Add SSL to apache virtualhost General.run_cmd("apt install certbot python3-certbot-apache -y") General.run_cmd("mkdir /var/lib/letsencrypt") General.run_cmd("chmod -R o+rx /var/lib/letsencrypt") General.output_message(""" -- Certbot configuration -- If questions are promp type the following answers: > Terms of service: A > Share mail address: N > redirect HTTP traffic to HTTPS: 2 > If the validation of the domain go wrong just exit the script and investigate on the problem. You can restart the script on the same domain and it will work correctly""") General.run_cmd_interactive(f"sudo certbot --apache -d {DOMAIN_FULL} -d www.{DOMAIN_FULL}") # runs interactive certbot configuration General.output_message('If certbot failed chek the apache2 logs ( Ubuntu: /var/log/apache2/error.log ) ') # wordpress virtualhost setup General.output_message("-- Configuring wordpress Db --") DB_NAME = General.input_message("Database Name ") DB_USER = General.input_message("Database User Name ") DB_USER_PASS = General.sensitive_input_message("Database User Password ") General.run_cmd( f""" mysql -e " CREATE DATABASE {DB_NAME} DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci; " """, f""" mysql -e " CREATE USER '{DB_USER}'@'localhost' IDENTIFIED BY '{DB_USER_PASS}'; " """, f""" mysql -e " GRANT ALL PRIVILEGES ON {DB_NAME}.* TO '{DB_USER}'@'localhost'; " """, """ mysql -e " FLUSH PRIVILEGES; " """ ) if(not os.path.exists('/tmp/wordpress')): General.output_message("\n-- WORDPRESS DOWNLOAD --") General.run_cmd("wget -P /tmp 'https://wordpress.org/latest.tar.gz' ") General.run_cmd("tar -C /tmp -zxvf /tmp/latest.tar.gz") General.run_cmd("touch /tmp/wordpress/.htaccess") General.run_cmd("cp /tmp/wordpress/wp-config-sample.php /tmp/wordpress/wp-config.php") General.run_cmd("mkdir /tmp/wordpress/wp-content/upgrade") General.run_cmd(f"cp -a /tmp/wordpress/. /var/www/{DOMAIN}") General.run_cmd(f"chown -R www-data:www-data /var/www/{DOMAIN}") General.run_cmd("find /var/www/" + DOMAIN + "/ -type d -exec chmod 750 {} \;") General.run_cmd("find /var/www/" + DOMAIN + "/ -type f -exec chmod 640 {} \;") f_wp_domain_config = f"/var/www/{DOMAIN}/wp-config.php" General.run_cmd("apt install curl -y") OUTPUT_KEYS = General.output_run_cmd("curl -s https://api.wordpress.org/secret-key/1.1/salt/").decode( "utf-8").split("');") for key in OUTPUT_KEYS: if key.strip() == '': OUTPUT_KEYS.remove(key) OUTPUT_KEYS_DICT = dict() for index, key in enumerate(OUTPUT_KEYS): index += 1 OUTPUT_KEYS_DICT["_" + str(index)] = [ '( '.join(key.split(",")[0].split('(')).strip() + ',', key.strip() + "');\n" ] General.change_lines( f_wp_domain_config, **OUTPUT_KEYS_DICT ) General.change_lines( f_wp_domain_config, _1=["define( 'DB_NAME',", f"define( 'DB_NAME', '{DB_NAME}');"], _2=["define( 'DB_USER',", f"define( 'DB_USER', '{DB_USER}');"], _3=["define( 'DB_PASSWORD',", f"define( 'DB_PASSWORD', '{DB_USER_PASS}');"], ) General.insert_lines( f_wp_domain_config, "define( 'FS_METHOD', 'direct');", index_surplus=1, anchor_line=f"define( 'DB_PASSWORD', 'DB_USER_PASS');" ) General.output_message('-- INFO --') General.output_message(f" > Finish the WP GUI installation going to https://{DOMAIN}") General.output_message(" > We did a setup for SSL certificate with Let’s Encrypt CERTBOT, THis Certificate expire") General.output_message(" after 90 days, A Bot that automatic does the renewal is also installed, Check that ") General.output_message(" it is working by typing 'sudo systemctl status certbot.timer' ") General.output_message(" > For check that PHP was installed sucesfully and it is working correctly do this steps: ") General.output_message(f" - sudo nano /var/www/{DOMAIN}/info.php") General.output_message(" - Add the following line to the file '<?php phpinfo(); ?>' ") General.output_message(f" - Visit this link 'http://{DOMAIN_FULL}/info.php'") General.output_message(f" If a table with php information was displayed and nothing went wrong remove the file\n" f" previously created 'sudo rm /var/www/{DOMAIN}/info.php'") time.sleep(5)
def setup(EMAIL): f_apache2_dir_conf = '/etc/apache2/mods-enabled/dir.conf' if not General.answer('Do you want to setup a wordpress server?'): return General.output_message("-- Starting LMAP Stack SETUP --") # Download LAMP Stack LINUX - APACHE - MYSQL - PHP # APACHE DOWNLOAD General.run_cmd('apt install apache2 -y') General.run_cmd('ufw allow in "Apache Full"') # MYSQL DOWNLOAD General.run_cmd('apt install mysql-server -y') # run mysql_secure_installation ( automated ) General.output_message("\n-- MYSQL SETUP --") MYSQL_ROOT_PASS = General.sensitive_input_message( "[MYSQL] Set root password") # Make sure that NOBODY can access the server without a password # Kill the anonymous users # Because our hostname varies we'll use some Bash magic here. # Kill off the demo database # Make our changes take effect # Any subsequent tries to run queries this way will get access denied because lack of usr/pwd param General.run_cmd( f""" mysql -e " ALTER USER 'root'@'localhost' IDENTIFIED BY '{MYSQL_ROOT_PASS}'; " """, """ mysql -e " DELETE FROM mysql.user WHERE user='' AND host='localhost'; " """, """ mysql -e " DROP USER ''@'$(hostname)'; " """, """ mysql -e " DROP DATABASE test; " """, """ mysql -e " FLUSH PRIVILEGES; " """) # PHP DOWNLOAD # php.ini : /etc/php/7.4/apache2/php.ini General.output_message("\n-- PHP SETUP --") General.run_cmd("apt install php libapache2-mod-php php-mysql -y") with open(f_apache2_dir_conf, 'w') as file: file.write(""" <IfModule mod_dir.c> DirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm </IfModule> """) General.run_cmd("sudo apt update -y") General.run_cmd( "sudo apt install php-curl php-gd php-mbstring php-xml php-xmlrpc php-soap php-intl php-zip -y" ) General.run_cmd("sudo systemctl restart apache2") General.run_cmd("systemctl restart apache2") # WORDPRESS DOWNLOAD General.output_message("\n-- WORDPRESS DOWNLOAD --") General.run_cmd("wget -P /tmp 'https://wordpress.org/latest.tar.gz' ") General.run_cmd("tar -C /tmp -zxvf /tmp/latest.tar.gz") General.run_cmd("touch /tmp/wordpress/.htaccess") General.run_cmd( "cp /tmp/wordpress/wp-config-sample.php /tmp/wordpress/wp-config.php") General.run_cmd("mkdir /tmp/wordpress/wp-content/upgrade")
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' )
def nvidia_drivers(): # Installation invidia driver response = General.answer('Do you need nvidia drivers?') if not response: return General.output_message('Since the nvidia-driver package in Debian is proprietary, we need to enable contrib and non-free component in /etc/apt/sources.list file') General.run_cmd('apt install software-properties-common') General.run_cmd('add-apt-repository contrib') General.run_cmd('add-apt-repository non-free') General.run_cmd('apt update -y') General.run_cmd('apt install nvidia-driver -y')
def ufw(SSH_ENABLE, SSH_PORT): # Firewall With UFW f_ufw_smtptls = '/etc/ufw/applications.d/smtptls' if not General.answer('Do you want install and configure UFW?'): return General.run_cmd('apt install ufw -y') General.run_cmd( 'ufw default deny outgoing comment "deny all outgoing traffic"', 'ufw default deny incoming comment "deny all incoming traffic"', 'ufw allow out 53 comment "allow DNS calls out"', 'ufw allow out 123 comment "allow NTP out"', 'ufw allow out http comment "allow HTTP traffic out"', 'ufw allow out https comment "allow HTTPS traffic out"', 'ufw allow out whois comment "allow whois"', 'ufw allow out 25 comment "allow MAIL out"') with open(f_ufw_smtptls, 'w') as file: file.write(''' [SMTPTLS] title=SMTP through TLS description=This opens up the TLS port 465 for use with SMPT to send e-mails. ports=465/tcp ''') General.run_cmd( 'ufw allow out smtptls comment "open TLS port 465 for use with SMPT to send e-mails"' ) General.output_message(''' The following ufw rules have been entered automatically: - deny all outgoing traffic - deny all incoming traffic - allow DNS calls out- - allow NTP out - allow HTTP traffic out - allow HTTPS traffic out - allow whois - allow SMPT out - allow MAIL out ''') # ufw ssh rules if SSH_ENABLE and General.answer('(UFW) Do you need ssh rule?'): General.run_cmd( f'ufw limit in {SSH_PORT} comment "allow SSH connections in"') General.output_message('Added Rules') # ufw ftp out rule if General.answer('(UFW) Do you need ftp out rule?'): General.run_cmd('ufw allow out ftp comment "allow FTP traffic out"') General.output_message('Added Rules') # ufw dhcp rule if General.answer('(UFW) Are you using DHCP?'): General.run_cmd( 'ufw allow out 68 comment "allow the DHCP client to update"') General.output_message('Added Rules') # ufw http/https rule if General.answer( '(UFW) Do you nedd to allow http/https ( yes for websites servers ) ?' ): General.run_cmd('ufw allow http comment "allow http traffic update"') General.run_cmd('ufw allow https comment "allow https traffic update"') General.output_message('Added Rules') General.output_message('Starting Firewall') General.warning_message('Maybe existing ssh connections will be stopped\n') General.warning_message( 'sometimes the next cmd get stuck so press ENTER after 1 minute') General.run_cmd('ufw --force enable')
def psad(EMAIL): # iptables Intrusion Detection And Prevention with f_psad_conf = '/etc/psad/psad.conf' f_before_rules = '/etc/ufw/before.rules' f_before6_rules = '/etc/ufw/before6.rules' if not General.answer('Do you want to install and configure psad?'): return General.run_cmd('apt install psad -y') homenet = General.input_message('Type your Home net: ex(192.168.1.1/24) ') General.output_message('Configuring psad') General.change_lines( f_psad_conf, _1=[ 'EMAIL_ADDRESSES root@localhost;', f'EMAIL_ADDRESSES {EMAIL};\n' ], _2=[ 'HOSTNAME _CHANGEME_;', f'HOSTNAME {General.HOSTNAME};\n' ], _3=[ 'ENABLE_AUTO_IDS N;', 'ENABLE_AUTO_IDS Y;\n' ], _4=[ 'HOME_NET any;', f'HOME_NET {homenet};\n' ], _5=[ 'PORT_RANGE_SCAN_THRESHOLD 1;', 'PORT_RANGE_SCAN_THRESHOLD 2;\n' ], _6=[ 'ENABLE_MAC_ADDR_REPORTING N;', 'ENABLE_MAC_ADDR_REPORTING Y;\n' ], _7=[ 'ALERT_ALL Y;', 'ALERT_ALL N;\n' ]) General.output_message(f''' These changes have been made to the config '/etc/psad/psad.conf'. If u need more advanced options feel free to modify it. - EMAIL_ADDRESSES {EMAIL}; - HOSTNAME {General.HOSTNAME}; - ENABLE_AUTO_IDS Y; - HOME_NET {homenet}; - PORT_RANGE_SCAN_THRESHOLD 2; - ENABLE_MAC_ADDR_REPORTING Y; - ALERT_ALL N; ''') with open(f_before_rules, 'r') as file: lines = file.readlines() text = file.read() if not (General.check_lines_in_file( f_before_rules, '# log all traffic so psad can analyze', '-A INPUT -j LOG --log-tcp-options --log-prefix "[IPTABLES]"', '-A FORWARD -j LOG --log-tcp-options --log-prefix "[IPTABLES]"' )): for index, line in enumerate(lines): if line.strip() == "COMMIT": lines.insert( index - 2, '# log all traffic so psad can analyze\n-A INPUT -j LOG --log-tcp-options --log-prefix "[IPTABLES]"\n-A FORWARD -j LOG --log-tcp-options --log-prefix "[IPTABLES]"' ) break with open(f_before_rules, 'w') as file: for line in lines: file.write(line) with open(f_before6_rules, 'r') as file: lines = file.readlines() text = file.read() if not (General.check_lines_in_file( f_before_rules, '# log all traffic so psad can analyze', '-A INPUT -j LOG --log-tcp-options --log-prefix "[IPTABLES]"', '-A FORWARD -j LOG --log-tcp-options --log-prefix "[IPTABLES]"' )): for index, line in enumerate(lines): if line.strip() == "COMMIT": lines.insert( index - 2, '# log all traffic so psad can analyze\n-A INPUT -j LOG --log-tcp-options --log-prefix "[IPTABLES]"\n-A FORWARD -j LOG --log-tcp-options --log-prefix "[IPTABLES]"' ) break with open(f_before6_rules, 'w') as file: for line in lines: file.write(line) General.warning_message('Restarting psad and Firewall..\n') General.warning_message('Maybe existing ssh connections will be stopped\n') General.run_cmd('ufw --force enable') General.run_cmd('ufw reload') subprocess.check_call(['psad', '-R'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) General.run_cmd('psad --sig-update') General.run_cmd('psad -H') General.output_message('Done')
def maldet(EMAIL): # Anti-Virus Scanning With Maldet dir_path = '/usr/local/src/' if not General.answer( 'Do you want to use Maldet for Anti-virus Scanning?'): return General.run_cmd( f'wget -q http://www.rfxn.com/downloads/maldetect-current.tar.gz -P {dir_path}' ) General.output_message("Maldet Downloaded") tarfile = '/usr/local/src/maldetect-current.tar.gz' path = '/usr/local/src/' retcode = subprocess.call(['tar', '-xvf', tarfile, '-C', path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for elem in listdir(dir_path): if ('maldetect-' in elem) and (not 'maldetect-current' in elem): maldect_path = dir_path + elem file_path = f'{maldect_path}/files/conf.maldet' General.run_cmd(f'sh {maldect_path}/install.sh') General.output_message('Maldet Installed') General.output_message('Configuring Maldet..') General.change_lines( file_path, _1=['email_alert="0"', 'email_alert="1"\n'], _2=['email_addr="*****@*****.**"', f'email_alert="{EMAIL}"\n'], _3=['email_ignore_clean="1"', 'email_ignore_clean="0"\n']) break