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 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 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 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])
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( "Also if you don't want to configure Exim4 we need your email for othe tools setup\nEmail" ) SSH_ENABLE = General.answer("Do you want to enable the SSH service?") if SSH_ENABLE: SSH_PORT = General.input_message( "Insert the port on which you want the ssh service to run, it will be used if you want to configure the ssh service" ) else: SSH_PORT = None # Main Terminal Menu
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' )