Secure a Server to CIS Level 1 - Script
Warning! Do not run this script on production machines until you have tested it in a sandbox/test environment first, this script will make changes to the overall function of the server
This is a very long script about 4000 lines that will run in a 5 to 10 minute window, depending on the server It my take a little less then 5 mins or a little more then 10 mins, if you get a black screen with nothing happening or just a spinner for more then 5 mins that's a sign that something is not working.
I added a interactive menu to collect most of the data and before you ask, none of that data stays after the script run, so you have to remember it, It is fairly easy securing your server using this script. since the standards continually change I will try to keep it as updated as possible.
This script was written for the OCI version of Oracle Linux 7 originally, but has expanded to cover other versions of RedHat and Ubuntu based Linux servers. I will include screen shots of the menus as well as a description of what its asking you for, you will notice that some of the scripts used here I split out of this script and on to other pages here.
You can download this script here or at the bottom of the page.
Clearing the scroll back buffer and setting the terminal
clear
export TERM=xterm-256color
User Configuration go here
############################
#### User Configuration ####
############################
RSWP=8 # <-- Set the required swap size
TCPPORTS=( 22 1521 5666 7001 7002 8000 9090 )
TCP6PORTS=( 22 )
UDPPORTS=( 53 )
UDP6PORTS=( 53 )
System Variables
##########################
#### System Variables ####
##########################
BACKUP="/root/config_Backups"
BOOTLD="/boot/grub2/user.cfg"
BOOTLDCE="/boot/efi/EFI/centos/"
BOOTLDRH="/boot/efi/EFI/redhat/"
BOOTLDUB="/boot/grub/user.cfg"
CRON_RH="/var/spool/cron/root"
CRON_UB="/var/spool/cron/crontab/root"
FIREIP="echo ${VLANIP// /}"
IPTBL="/etc/sysconfig/iptables"
IP6TBL="/etc/sysconfig/ip6tables"
IPTBLUB="/etc/iptables/rules.v4"
IP6TBLUB="/etc/iptables/rules.v6"
GRUBCFG="/boot/grub2/grub.cfg"
GRUBCFGCE="/boot/efi/EFI/centos/grub.cfg"
GRUBCFGRH="/boot/efi/EFI/redhat/grub.cfg"
GRUBCFGUB="/boot/grub/grub.cfg"
HOST=$(uname -n | awk -F. '{print $1}')
HOSTNAME=$(uname -n)
IPADD=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1')
LOG=${BACKUP}/install.log
MODPRO="/etc/modprobe.d/cis.conf"
MYIP=$(netstat -putan | awk '/:22 / && /ESTABLISHED/ {split($5,result,":"); print result[1]}')
TMPMNT="/usr/lib/systemd/system"
OS=$(grep PRETTY_NAME /etc/os-release | sed 's/PRETTY_NAME=//g' | tr -d '="' | awk '{print $1}' | tr '[:upper:]' '[:lower:]')
OSVER=$(grep VERSION_ID /etc/os-release | sed 's/VERSION_ID=//g' | tr -d '="' | awk -F. '{print $1}')
Menu Variables
########################
#### Menu Variables ####
########################
H1=20
R1=3
R2=6
R3=11
W1=80
Detect OS, OS Version and set package manager
###########################################################
#### Detect Package Manger from OS and OSVer Variables ####
###########################################################
if [ "${OS}" = ubuntu ]; then
PAKMGR="apt-get -y"
elif [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle || ${OS} = rocky || ${OS} = alma ]]; then
if [ "${OSVER}" = 7 ]; then
PAKMGR="yum -y"
fi
if [ "${OSVER}" = 8 ] || [ "${OSVER}" = 9 ]; then
PAKMGR="dnf -y"
fi
fi </code
Making sure you are a root user, won't work otherwise
##############################################
#### Check to see if running as Root User ####
##############################################
function check_root() {
{
if [ $EUID -ne 0 ]; then
echo ""
echo "Script Installation has been Halted!"
echo ""
echo "You Must Run This Script as the \"ROOT\" User"
exit
fi
}
}
Create the Backup /dir and log file
#################################
#### Config backup directory ####
#################################
function backup() {
{
for dir in ${BACKUP}; do
[[ ! -d "$dir" ]] && mkdir "$dir"
touch ${BACKUP}/install.log
done
}
}
I use this function in place of cat and echo from time to time it works best for files that have no indenting.
#######################
#### Copy Function ####
#######################
function no_show() {
{
expand | awk 'NR == 1 {match($0, /^ */); l = RLENGTH + 1}
{print substr($0, l)}'
}
}
Spinner Function - Gives you something to else to watch :-)
##########################
#### Spinner Function ####
##########################
function _spinner() {
{
local on_success="COMPLETE"
local on_fail="ERROR"
local green="\e[1;32m"
local red="\e[1;31m"
local nc="\e[0m"
case $1 in
start)
((column=$(tput cols)-${#2}-8))
echo -ne "\e[7m ${2} \e[0m \n"
printf "%${column}s"
i=1
sp='/-\|/-\:'
delay=${SPINNER_DELAY:-0.15}
while :
do
printf "\b%s${sp:i++%${#sp}:1}"
sleep "$delay"
done
;;
stop)
if [[ -z ${3} ]]; then
echo "spinner is not running.."
exit 1
fi
kill "$3" > /dev/null 2>&1
echo -en "\b["
if [[ $2 -eq 0 ]]; then
echo -en "${green}${on_success}${nc}"
else
echo -en "${red}${on_fail}${nc}"
fi
echo -e "]"
;;
*)
echo "invalid argument, try {start/stop}"
exit 1
;;
esac
}
}
Spinner Start Function
#######################
#### Spinner Start ####
#######################
function start_spinner {
{
echo ""
_spinner "start" "${1}" &
_sp_pid=$!
echo ""
disown
}
}
Spinner Stop Function
######################
#### Spinner Stop ####
######################
function stop_spinner {
{
echo ""
_spinner "stop" "$1" $_sp_pid
unset _sp_pid
echo ""
}
}
First Message on Start of script - "Warning! Message"
#########################
#### Warning Message ####
#########################
function warn_message() {
{
whiptail --backtitle "SecureIt contact@mylinux.work" --title "*** WARNING ***" --yes-button "CONFIRM" --no-button "Exit" --defaultno --yesno " Running this script will harden this server to CIS Benchmark settings.
It will change server configuration and will affect server operation
ONLY RUN THIS SCRIPT IF YOU KNOW WHAT YOU ARE DOING!
You must select CONFIRM to continue." ${H1} ${W1}
exitstatus=$?
if [ ${exitstatus} = 0 ]; then
private_ip
else
exit
fi
}
}
I will point out at this point that when you run this on a Ubuntu OS based machine the background will be pink if you run this on a RedHat OS based machine the background will be blue, Just so you know....
What is the connection IP - "Private IP Menu"
#############################
#### Get VLAN IP address ####
#############################
function private_ip() {
{
VLANIP=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Server Connect IP" --ok-button "Continue" --cancel-button "Exit" --inputbox " What is the IP/Sub or VLAN/Sub you use to connect to this server?
Examples are 192.168.0.0/24
or 192.168.1.21/32
or 10.0.10.0/16
Your current SSH Connection IP is Shown and can be changed if required" ${H1} ${W1} "${MYIP}"/32 3>&1 1>&2 2>&3)
exitstatus=$?
if [ ${exitstatus} = 0 ]; then
time_zone
else
exit
fi
}
}
The address you see here is auto detected, It should be the address you used to connect with like a VPN if private network or the public address you connected to the machine with.
This is very IMPORTANT! the IP address that is in this box will be the only address in the hosts.allow file so if you make a mistake here you will have to console connect to the server to fix it cause you won't be able to get in any other way.
You can have more addresses here if you need like multi IP, machines, vlans or subnets. Examples are listed on the menu screen, multi IP's are done like this 192.168.1.10/32, 192.168.2.10/32, 192.168.3.21/32 and so....
What is the Server Timezone - "Get Timezone Menu"
######################
#### Get TimeZone ####
######################
function time_zone() {
{
# shellcheck disable=SC2046
TIMEZONE=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Server TimeZone" --ok-button "Continue" --cancel-button "Exit" --menu " What is your Server Timezone?
Example Central" ${H1} ${W1} ${R3} $(find /usr/share/zoneinfo/US/* | cut -d '/' -f 6 | sort | sed "s/$/ ./" | tr '\n' ' ';) 3>&1 1>&2 2>&3)
exitstatus=$?
if [ ${exitstatus} = 0 ]; then
max_count
else
exit
fi
}
}
This gets the timezone variable which is used at the beginning of the scripts run to set the servers timezone, This is done more for the logs to make it easier to narrow done the time frames for problems or finding selinux issue with auditctl, I only loaded the major time zones for simplicity.
Auto logout/Disconnect Time - "Server Disconnect Menu"
##################################
#### Get Auto Disconnect Time ####
##################################
function max_count() {
{
MAXCOUNT=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Server Disconnect" --ok-button "Continue" --cancel-button "Exit" --radiolist " What is the MAX time you want before auto disconnect?" ${H1} ${W1} ${R1} \
"1" "5 mins" OFF \
"2" "10 mins" OFF \
"3" "15 mins" ON 3>&1 1>&2 2>&3)
exitstatus=$?
if [ ${exitstatus} = 0 ]; then
max_logs
else
exit
fi
}
}
CIS recommends 5 mins, but I have defaulted this to 15 mins, for those of you that don't know, this is the amount of keyboard input time inactivity.. The problem I have with this is Oracle updates, and the DBA's I support would get logged out before the script to update Oracle was finished, so I defaulted it to 15 mins and then came up with a work around for the oracle and applmgr users so this would no longer be an issue. Since I mentioned I have a work around you can email me and I'll give it to you.
Select your log type - "Audit Logs Menu"
#################################
#### Get Audit logs Setting ####
################################
function max_logs() {
{
MAXLOGS=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Audit Logs" --ok-button "Continue" --cancel-button "Exit" --inputbox " If you plan on archiving the audit logs leave \"ignore\" here
If you have tons of room change this to \"KEEP_LOGS\"" ${H1} ${W1} ignore 3>&1 1>&2 2>&3)
exitstatus=$?
if [ ${exitstatus} = 0 ]; then
syslog_server
else
exit
fi
}
}
I think this is self explanatory I have an audit log script that installs with the SecureIt.sh script that will compress the daily logs to a more manageable size, you'll see it later in this doc....
What's your syslog servers name or IP address - "SysLog Server Menu"
###########################
#### Get Syslog Server ####
###########################
function syslog_server() {
{
SYSLOG=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "SysLog Server" --ok-button "Continue" --cancel-button "Exit" --inputbox " What is the Name or IP of your SysLog Server?" ${H1} ${W1} 3>&1 1>&2 2>&3)
exitstatus=$?
if [ ${exitstatus} = 0 ]; then
srv_type
else
exit
fi
}
}
Again self explanatory, but required. (NOTE: to pass Nessus Scan this must match what you have configured Nessus to find)
What's this server used for - "Server Usage Menu"
##########################
#### Get Server Usage ####
##########################
function srv_type() {
{
SRVTYPE=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Server Disconnect" --ok-button "Continue" --cancel-button "Exit" --radiolist " What is the use or purpose of this server?" ${H1} ${W1} ${R1} \
"1" "EBS Server" OFF \
"2" "Weblogic Server" OFF \
"3" "Regular Server" ON 3>&1 1>&2 2>&3)
exitstatus=$?
if [ ${exitstatus} = 0 ]; then
grub_password
else
exit
fi
}
}
When I built this script originally, it was for some oracle dba's, I had originnally left out most the security stuff like the grub password, the syslog server and a few I can't mention, but it was an easy provisioning tool that they could use if needed. I have since removed more of the user configurable's and added additional menu's for a more secure run for a sysadmin's use.
Short description of the this menu and what they do...
- EBS Server - Thest installs all the prereq's for you to be able to run Oracle EBS on the server.
- Weblogic Server - This also installs the prereq's needed for Oracle EBS, but it also has some config changes that must be done so that Weblogic will run in the secured environment.
- Regular Server - Is Just that a server that isn't running any apps that are affected by the secured server.
Get a Grub Password - "Grub Password Menu"
#########################
#### Get Grub Passwd ####
#########################
function grub_password() {
{
GPASS=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Grub Password" --ok-button "Continue" --cancel-button "Exit" --inputbox " What do you want your Grub Password to be?" ${H1} ${W1} 3>&1 1>&2 2>&3)
exitstatus=$?
if [ ${exitstatus} = 0 ]; then
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle ]]; then
G2PASSWD="$(echo -e "${GPASS}\n$GPASS" | grub2-mkpasswd-pbkdf2 2>/dev/null | tail --lines=1 | awk -F " " '{print $7}')"
main_menu
elif [ "${OS}" = ubuntu ]; then
G2PASSWD="$(echo -e "${GPASS}\n$GPASS" | grub-mkpasswd-pbkdf2 2>/dev/null | tail --lines=1 | awk -F " " '{print $7}')"
main_menu
fi
else
exit
fi
}
}
Important! Note - Be sure you put something secure here and that you write it down or remember it otherwise you will not be able to boot in safe mode through the console connection.
OS selection happens here - "OS Select Main" Menu
#############################
#### OS Select Main Menu ####
#############################
function main_menu() {
{
while true; do
CHOICE=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "OS Select Main" --ok-button "Continue" --cancel-button "Exit" --menu " Please Select Your Linux Distro" ${H1} ${W1} ${R2} \
"1)" "Oracle Linux" \
"2)" "RedHat/CentOS/Rocky/Alma" \
"3)" "Ubuntu *** Testing ***" 3>&2 2>&1 1>&3)
exitstatus=$?
if [ ${exitstatus} = 0 ]; then
case ${CHOICE} in
"1)")
oracle_menu
;;
"2)")
redhat_menu
;;
"3)")
ubuntu_menu
;;
"4)")
;;
esac
else
exit
fi
done
}
}
Select the type of OS you are trying to harden.
Oracle Selection Menu
#####################
#### Oracle Menu ####
#####################
function oracle_menu() {
{
while true; do
CHOICE=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Oracle Linux" --ok-button "Install" --cancel-button "Exit" --menu " Please Select Your Oracle Version" ${H1} ${W1} ${R2} \
"1)" "OCI Oracle Linux 7" \
"2)" "OCI Oracle Linux 8" \
"3)" "Oracle Linux 7" \
"4)" "Oracle Linux 8" 3>&2 2>&1 1>&3)
exitstatus=$?
if [ ${exitstatus} = 0 ]; then
case ${CHOICE} in
"1)")
oci_oracle_ebs_setup
oci_rh_ub_common
oci_only
complete
;;
"2)")
oci_oracle_ebs_setup
oci_rh_ub_common
oci_only
complete
;;
"3)")
oci_rh_ub_common
complete
;;
"4)")
oci_rh_ub_common
complete
;;
esac
else
exit
fi
done
}
}
If you have played on the Oracle Cloud then you will know what OCI refers to, There are some firewall rules that are required for the OCI, hence it's own listing, same with AWS which has the same requirement on their cloud, well not the same but similar firewall requirement, All other cloud and none cloud servers select the regular ones.
Redhat Selection Menu
#####################
#### Redhat Menu ####
#####################
function redhat_menu() {
{
while true; do
CHOICE=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Redhat/Centos Linux" --ok-button "Install" --cancel-button "Exit" --menu " Please Select Your Redhat/CentOS Version" ${H1} ${W1} ${R2} \
"1)" "OCI CentOS 7" \
"2)" "OCI CentOS 8" \
"3)" "AWS Redhat/Centos 7" \
"4)" "AWS Redhat/Centos 8" \
"5)" "Redhat/CentOS/Rocky/Alma 7" \
"6)" "Redhat/CentOS/Rocky/Alma 8" \
"7)" "Redhat/Centos/Rocky/Alma 9" 3>&2 2>&1 1>&3)
exitstatus=$?
if [ ${exitstatus} = 0 ]; then
case ${CHOICE} in
"1)")
oci_rh_ub_common
oci_only
complete
;;
"2)")
oci_rh_ub_common
oci_only
complete
;;
"3)")
oci_rh_ub_common
aws_only
complete
;;
"4)")
oci_rh_ub_common
aws_only
complete
;;
"5)")
oci_rh_ub_common
complete
;;
"6)")
oci_rh_ub_common
complete
;;
"7)")
oci_rh_ub_common
complete
;;
esac
else
exit
fi
done
}
}
Same here, if your not on OCI or AWS just select the the regular ones for all other cloud providers and regular servers....
Ubuntu Selection Menu
######################
#### Ubuntu Menu ####
#####################
function ubuntu_menu() {
{
while true; do
CHOICE=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Ubuntu Linux" --ok-button "Install" --cancel-button "Exit" --menu " Please Select Your Ubuntu Version" ${H1} ${W1} ${R2} \
"1)" "OCI Ubuntu" \
"2)" "AWS Ubuntu" \
"2)" "Ubuntu" 3>&2 2>&1 1>&3)
exitstatus=$?
if [ ${exitstatus} = 0 ]; then
case ${CHOICE} in
"1)")
oci_rh_ub_common
oci_only
complete
;;
"2)")
oci_rh_ub_common
aws_only
complete
;;
"3)")
oci_rh_ub_common
complete
;;
esac
else
exit
fi
done
}
}
Just like the other 2, you just need to select the last entry if you are on any other cloud service, like Digital Ocean, Contabo or Linode.
There is one other screen that will pop up at the end of the install, the completion screen, I will include it at the end of the doc for your viewing pleasure :-)
I have a few extra things in here like the mkswap function and a few utilities that are done after the server is hardened, like unattended security updates, a message of the day, cursor colors, audit compression script, SysStat, rkhunter, logwatch and lmd just to name a few... So on with the code!
Mkswap function
#############################
#### Make Swap if Needed ####
#############################
function make_swap() {
{
start_spinner 'Configuring Additional Swap Space...'
echo ""
if [ "${SRVTYPE}" -ne 3 ]; then
# size of swapfile in gigabytes
swpsize="$RSWP"
# how large the swap needs to be total in mb's
swpneed=$((swpsize * 1024))
# / part dir file list
dir=$(ls -la --block-size=M /)
# does the swap file already exist?
swpexist=$(echo "$dir" | grep -i swap | awk '{ print $5 }' | tr -d 'M"')
# what is the name of the swap file if it exist
swpname=$(echo "$dir" | grep -i swap | awk '{ print $9 }')
# Is there any swap present if yes what size is it
swppres=$(free -m | sed -n '3 p' | awk '{ print $2 }')
# If the swap file already exist is it large enough?
if (( swpneed < swpexist )) || (( swpneed < swppres )); then
echo -e '\e[01;37m ======================================================================='
echo -e '\e[01;32m ====================================================================='
echo -e '\e[01;32m ==== \e[01;37m A Large Enough Swapfile was Found! No Changes Needed... \e[01;32m ===='
echo -e '\e[01;32m ====================================================================='
echo -e '\e[01;37m ======================================================================='
elif (( swpneed > swpexist )) || (( swpneed > swppres )); then
echo -e '\e[01;37m =================================================================================='
echo -e '\e[01;31m ================================================================================'
echo -e '\e[01;31m ==== \e[01;37m A Large Enough Swapfile was not found! Creating Larger SwapFile... \e[01;31m ===='
echo -e '\e[01;31m ================================================================================'
echo -e '\e[01;37m =================================================================================='
# Turn off existing swap if needing replacement
if echo "$dir" | grep -i swap; then
swapoff /"${swpname}"
rm -f /"$swpname"
fi
# Create the swapfile and make it active
fallocate -l ${swpsize}g /.SwapFile
chmod 600 /.SwapFile
mkswap /.SwapFile
swapon /.SwapFile
echo -e '\e[01;37m =============================================================================='
echo -e '\e[01;32m ============================================================================'
echo -e '\e[01;32m ==== \e[01;37m Checking whether the swap space was mounted and active or not! \e[01;32m ===='
echo -e '\e[01;32m ============================================================================'
echo -e '\e[01;37m =============================================================================='
R=$(swapon -s)
if [ -n "$R" ]; then
echo -e '\e[01;32m ============'
echo -e '\e[01;32m ============'
echo -e '\e[01;32m ============================================================================'
echo -e "\e[01;37m$R"
echo -e '\e[01;32m ============================================================================'
echo -e '\e[01;37m =============================================================================='
else
echo -e '\e[01;31m ============'
echo -e '\e[01;31m ============'
echo -e '\e[01;31m ============================================================================'
echo -e "\e[01;37m Something Went Wrong no Swap was Loaded"
echo -e '\e[01;31m ============================================================================'
echo -e '\e[01;37m =============================================================================='
fi
# Check to see if the created swap is losted in the fstab file
if ! grep -q "SwapFile" /etc/fstab; then
echo "/.SwapFile swap swap defaults 0 0" >> /etc/fstab
fi
fi
fi
stop_spinner $?
} | tee -a $LOG
}
Swap is configured first the size is set in the user configuration section, this is not a CIS requirement, but gets overlooked often.
Timezone function
############################
#### Set Sever TimeZone ####
############################
function time_set() {
{
start_spinner 'Setting System TimeZone...'
echo ""
timedatectl set-timezone US/"${TIMEZONE}"
stop_spinner $?
} | tee -a $LOG
}
This is set with the menu "Get TimeZone" variable.
Section 1.1.1 Unused File Systems
########################################
### 1.1.1 Disable Unused Filesystems ###
########################################
function disable_filesystems() {
{
start_spinner 'Disabling Unused Filesystems...'
echo ""
touch ${MODPRO}
#### 1.1.1.1 Ensure mounting of cramfs is disabled ####
echo "install cramfs /bin/true" > ${MODPRO}
lsmod | grep -qi cramfs
if [ $? != 1 ]; then
rmmod cramfs
fi
#### 1.1.1.2 Ensure mounting of freevxf filesystem 1s disabled ####
echo "install freevxfs /bin/true" >> ${MODPRO}
lsmod | grep -qi freevxfs
if [ $? != 1 ]; then
rmmod freevxfs
fi
#### 1.1.1.3 Ensure mounting of jiffs2 filesystem is disabled ####
echo "install jffs2 /bin/true" >> ${MODPRO}
lsmod | grep -qi jffs2
if [ $? != 1 ]; then
rmmod jffs2
fi
#### 1.1.1.4 Ensure mounting of hfs filesystem is disabled ####
echo "install hfs /bin/true" >> ${MODPRO}
lsmod | grep -qi hfs
if [ $? != 1 ]; then
rmmod hfs
fi
#### 1.1.1.5 Ensure mounting of hfsplus filesystem is disabled ####
echo "install hfsplus /bin/true" >> ${MODPRO}
lsmod | grep -qi hfsplus
if [ $? != 1 ]; then
rmmod hfsplus
fi
#### 1.1.1.6 Ensure mounting of squashfs filesystem is disabled ####
echo "install squashfs /bin/true" >> ${MODPRO}
lsmod | grep -qi squashfs
if [ $? != 1 ]; then
rmmod squashfs
fi
#### 1.1.1.7 Ensure mounting of udf filesystem is disabled ####
echo "install udf /bin/true" >> ${MODPRO}
lsmod | grep -qi udf
if [ $? != 1 ]; then
rmmod udf
fi
#### 1.1.1.8 Ensure mounting of FAT filesystem is disabled ####
echo "install fat /bin/true" >> ${MODPRO}
lsmod | grep -qi fat
if [ $? != 1 ]; then
rmmod fat
fi
#####################################
#### Additonal Unsed Filesystems ####
#####################################
echo "install cifs /bin/true" >> ${MODPRO}
lsmod | grep -qi cifs
if [ $? != 1 ]; then
rmmod cifs
fi
echo "install nfs /bin/true" >> ${MODPRO}
lsmod | grep -qi nfs
if [ $? != 1 ]; then
rmmod nfs
fi
echo "install nfsv3 /bin/true" >> ${MODPRO}
lsmod | grep -qi nfsv3
if [ $? != 1 ]; then
rmmod nfsv3
fi
echo "install nfsv4 /bin/true" >> ${MODPRO}
lsmod | grep -qi nfsv4
if [ $? != 1 ]; then
rmmod nfsv4
fi
echo "install gfs2 /bin/true" >> ${MODPRO}
lsmod | grep -qi gfs2
if [ $? != 1 ]; then
rmmod gfs2
fi
echo "install usb-storage /bin/true" >> ${MODPRO}
lsmod | grep -qi usb-storage
if [ $? != 1 ]; then
rmmod usb-storage
fi
echo "install bnep /bin/true" >> ${MODPRO}
lsmod | grep -qi bnep
if [ $? != 1 ]; then
rmmod bnep
fi
echo "install bluetooth /bin/true" >> ${MODPRO}
lsmod | grep -qi bluetooth
if [ $? != 1 ]; then
rmmod bluetooth
fi
echo "install btusb /bin/true" >> ${MODPRO}
lsmod | grep -qi btusb
if [ $? != 1 ]; then
rmmod btusb
fi
echo "install net-pf-31 /bin/true" >> ${MODPRO}
lsmod | grep -qi net-pf-31
if [ $? != 1 ]; then
rmmod net-pf-31
fi
echo "install appletalk /bin/true" >> ${MODPRO}
lsmod | grep -qi appletalk
if [ $? != 1 ]; then
rmmod appletalk
fi
{
echo "blacklist usb-storage"
echo "blacklist firewire-core"
echo "options ipv6 disable=1"
} >> ${MODPRO}
stop_spinner $?
} | tee -a $LOG
}
Section 1 of the CIS manual, kills all of these services, under additional I have added some additional services that several of the companies I worked with decided to also kill, I will warn you now tough if you have any NFS mounts you might want to comment out the NFS and NFv3 from the additional's section.
Section 1.1.2 Ensure Separate Partitions
######################################################
#### 1.1.2 Ensure seprate partion exists for /tmp ####
######################################################
function tmp_directory() {
{
start_spinner 'Ensuring a Seprate Partion Exists for /tmp...'
echo ""
#### Copy Conf Files for Backup ####
xargs -n 1 cp -v /etc/fstab <<< ""${BACKUP} /etc/fstab.bak""
#### Check to see if /tmp is a mount ####
mount | grep /tmp
if ! 1; then
umount /tmp
fi
#### /tmp Mount Changes Ubuntu ####
if [ "${OS}" = ubuntu ]; then
xargs -n 1 cp -v /usr/share/systemd/tmp.mount <<< ""${BACKUP} /usr/share/systemd/tmp.mount.bak""
grep nosuid /usr/share/systemd/tmp.mount
if ! 1; then
sed -i 's/Options=mode=1777,strictatime,nosuid,nodev/Options=mode=1777,strictatime,nosuid,nodev,noexec/g' /usr/share/systemd/tmp.mount
else
sed -i 's/Options=mode=1777,strictatime/Options=mode=1777,strictatime,nosuid,nodev,noexec/g' /usr/share/systemd/tmp.mount
fi
#### /tmp Mount Changes RedHat ####
elif [ "${OS}" = oracle ]; then
xargs -n 1 cp -v /usr/lib/systemd/system/tmp.mount <<< ""${BACKUP} /usr/lib/systemd/system/tmp.mount.bak""
if [ "${OSVER}" = 7 ]; then
sed -i 's/Options=mode=1777,strictatime/Options=mode=1777,strictatime,nosuid,nodev,noexec/g' $TMPMNT/tmp.mount
fi
if [ "${OSVER}" = 8 ] || [ "${OSVER}" = 9 ]; then
sed -i 's/Options=mode=1777,strictatime,nosuid,nodev/Options=mode=1777,strictatime,nosuid,nodev,noexec/g' $TMPMNT/tmp.mount
fi
elif [[ ${OS} = centos || ${OS} = redhat || ${OS} = rocky || ${OS} = alma ]]; then
if [ "${OSVER}" = 7 ]; then
sed -i 's/Options=mode=1777,strictatime/Options=mode=1777,strictatime,nosuid,nodev,noexec/g' $TMPMNT/tmp.mount
fi
if [ "${OSVER}" = 8 ]; then
sed -i 's/Options=mode=1777,strictatime,nosuid,nodev/Options=mode=1777,strictatime,nosuid,nodev,noexec/g' $TMPMNT/tmp.mount
fi
if [ "${OSVER}" = 9 ]; then
sed -i 's/Options=mode=1777,strictatime,nosuid,nodev,size=50%,nr_inodes=1m/Options=mode=1777,strictatime,nosuid,nodev,noexec,size=50%,nr_inodes=1m/g' $TMPMNT/tmp.mount
fi
else
xargs -n 1 cp -v /etc/systemd/system/local-fs.target.wants/tmp.mount <<< ""${BACKUP} /etc/systemd/system/local-fs.target.wants/tmp.mount.bak""
no_show << EOF > /etc/systemd/system/local-fs.target.wants/tmp.mount
[Mount]
What=tmpfs
Where=/tmp
Type=tmpfs
Options=mode=1777,strictatime,noexec,nodev,nosuid
EOF
fi
#### Setting /tmp to persist thru reboots ####
if ! grep -w /tmp /etc/fstab; then
echo "tmpfs /tmp tmpfs defaults,nodev,nosuid,noexec 0 0" >> /etc/fstab
fi
mount /tmp
#### 1.1.3, 1.1.4 & 1.1.5 Ensure noexec, nosuid and nodev option set on /tmp partition ####
#### mount -o remount,noexec,nosuid,nodev /tmp
#### Setting /var/tmp to persist thru reboots ####
if ! grep -w /var/tmp /etc/fstab; then
echo "/tmp /var/tmp none rw,noexec,nosuid,nodev,bind 0 0" >> /etc/fstab
fi
#### Binding mount /var/tmp directory to /tmp ####
mount -o rw,noexec,nosuid,nodev,bind /tmp/ /var/tmp/
#### 1.1.8, 1.1.9 & 1.1.10 Ensure noexec, nosuid and nodev option set on /var/tmp partition ####
mount -o remount,noexec,nosuid,nodev /var/tmp
#### Setting /dev/shm to persist thru reboots ####
if [ "${SRVTYPE}" -ne 2 ]; then
if ! grep -w /dev/shm /etc/fstab; then
echo "tmpfs /dev/shm tmpfs defaults,nodev,nosuid,noexec,relatime 0 0" >> /etc/fstab
#### 1.1.15, 1.1.16 and 1.1.17 Ensure noexec, nosuid and nodev option set on /dev/shm partition ####
mount -o remount,noexec,nosuid,nodev,relatime /dev/shm
fi
fi
#### Ensure noexec and nodev option set on /dev partition ####
mount -o remount,noexec /dev
#### Setting /dev to persist thru reboots ####
if ! grep -w devtmpfs /etc/fstab; then
echo "devtmpfs /dev devtmpfs defaults,noexec 0 0" >> /etc/fstab
fi
stop_spinner $?
} | tee -a $LOG
}
Before you say anything, I know /home is not in here, but what VPS has a separate /home on it without you creating it in your custom image or manually on the cloud server? And YES Nessus dings you for that with a Failed
Section 1.1.21 Ensure Sticky Bit is Set
#############################################################################
#### 1.1.21 Ensure Sticky Bit is set on "All" World-Writable Directories ####
#############################################################################
function stickybit() {
{
start_spinner 'Setting Sticky Bit on "All" World-Writable Directories...'
echo ""
df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type d -perm -0002 2>/dev/null | xargs chmod a+t
stop_spinner $?
} | tee -a $LOG
}
Required - Sticky bit on all World Writable /dirs.
Section 1.1.22 Ensure GPG Keys are configured
##############################################
#### 1.2.2 Ensure GPG Keys are Configured ####
##############################################
function gpgkeys() {
{
start_spinner 'Checking GPG Keys are Configured...'
echo ""
if [ "${OS}" = ubuntu ]; then
apt-cache policy
${PKGMGR} update 2>&1 1>/dev/null | sed -ne 's/.*NO_PUBKEY //p' |
while read -r key; do
echo 'Processing key:' "$key"
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys "$key"
done
apt-key adv --refresh-keys --keyserver keyserver.ubuntu.com
apt-key list
else
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY*
rpm -q gpg-pubkey --qf '%{name}-%{version}-%{release} --> %{summary}\n'
grep ^gpgcheck /etc/yum.repos.d/* >> ${LOG} 2>&1
### 1.2.3 Verify that gpgcheck is Globally Activated ###
grep -Eq "^(\s*)gpgcheck\s*=\s*\S+(\s*#.*)?\s*$" /etc/yum.conf && sed -ri "s/^(\s*)gpgcheck\s*=\s*\S+(\s*#.*)?\s*$/\1gpgcheck=1\2/" /etc/yum.conf || echo "gpgcheck=1" >> /etc/yum.conf
fi
stop_spinner $?
} | tee -a $LOG
}
This just makes sure that all the repo's have a current cert and gpgceck=1 is set, even though this is configured correctly, Nessus will still give you a warning Warning to check it...
Section 1.3.1 Ensure Aide is Installed
########################################
#### 1.3.1 Ensure Aide is Installed ####
########################################
function aide_install() {
{
start_spinner 'Installing and Configuring AIDE...'
echo ""
if [ "${OS}" = ubuntu ]; then
debconf-set-selections <<< ""postfix postfix/mailname string "${HOSTNAME}"""
debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'"
${PAKMGR} install aide aide-common --assume-yes
aideinit
update-aide.conf
if [ ! -f ${CRON_UB} ]; then
touch ${CRON_UB}
crontab ${CRON_UB}
fi
if ! grep -qi "aide" ${CRON_UB}; then
echo "0 5 * * * /usr/bin/aide.wrapper --check" >> ${CRON_UB}
fi
else
${PAKMGR} install aide
aide --init
mv -f /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
if [ ! -f ${CRON_RH} ]; then
touch ${CRON_RH}
crontab ${CRON_RH}
fi
if ! grep -qi "aide" ${CRON_RH}; then
echo "0 5 * * * /usr/sbin/aide --check" >> ${CRON_RH}
fi
fi
stop_spinner $?
} | tee -a $LOG
}
Aide is a requirement to a secure environment, I also split this off from the sudo requirement for clarity in the script.
Section 1.3 Sudo Commands
###########################
#### 1.3 Sudo Commands ####
###########################
function sudo_changes() {
{
start_spinner 'Configuring Sudo Settings...'
echo ""
if [ ! -f /etc/sudoers.d/cis ]; then
touch /etc/sudoers.d/cis
chmod 440 /etc/sudoers.d/cis
fi
#### 1.3.2 Ensure Sudo Commands use Pty ####
echo "Defaults use_pty" >> /etc/sudoers.d/cis
#### 1.3.3 Ensure Sudo Log File Exists ####
echo "Defaults logfile=\"/var/log/sudo.log\"" >> /etc/sudoers.d/cis
stop_spinner $?
} | tee -a $LOG
}
Required - this just creates a file in the /sudoers.d dir called cis and copies the pty and log file requirements in there to track sudo users
Section 1.4 Secure Boot Settings
##################################
#### 1.4 Secure Boot Settings ####
##################################
function boot_load() {
{
start_spinner 'Securing Boot Settings...'
echo ""
#### 1.4.1 Ensure permissions on bootloader config are configured ####
if [ "${OS}" = "ubuntu" ]; then
touch ${BOOTLDUB}
chmod 600 ${BOOTLDUB}
chown root.root ${BOOTLDUB}
else
touch ${BOOTLD}
chmod 600 ${BOOTLD}
chown root.root ${BOOTLD}
fi
#### Config /boot/efi permissions in fstab !!! This is for OCI !!! I have not seen this on any other cloud provider ####
mount | grep /boot/efi
if [ $? != 1 ]; then
umount /boot/efi
if [ "${OS}" = oracle ]; then
if [ "${OSVER}" = 7 ]; then
sed -i 's/defaults,uid=0,gid=0,umask=0077,shortname=winnt,_netdev,_netdev,x-initrd.mount/defaults,uid=0,gid=0,umask=0077,fmask=0177,shortname=winnt,_netdev,_netdev,x-initrd.mount/g' /etc/fstab
elif [ "${OSVER}" = 8 ]; then
sed -i 's/defaults,uid=0,gid=0,umask=077,shortname=winnt/defaults,uid=0,gid=0,umask=077,fmask=0177,shortname=winnt/g' /etc/fstab
fi
fi
if [ "${OS}" = centos ]; then
sed -i 's/vfat[[:blank:]]*defaults/vfat defaults,uid=0,gid=0,umask=0077,fmask=0177/g' /etc/fstab
fi
mount /boot/efi
fi
#### 1.4.2 Ensure bootloader password is set ####
if [ "${OS}" = centos ]; then
echo GRUB2_PASSWORD="${G2PASSWD}" > ${BOOTLD}
cp ${BOOTLD} ${BOOTLDCE}
elif [ "${OS}" = ubuntu ]; then
echo GRUB2_PASSWORD="${G2PASSWD}" > ${BOOTLDUB}
else
echo GRUB2_PASSWORD="${G2PASSWD}" > ${BOOTLD}
cp ${BOOTLD} ${BOOTLDRH}
fi
stop_spinner $?
} | tee -a $LOG
}
This sets permissions on the user.cfg file, then sets the password hash that was created earlier when you were asked what you wanted the boot password to be,
What I didn't mention is the section that configures the /boot/efi dir, The OCI configures and load the OS as a UEFI hence the EFI configuration (or eps flag parameter), I have not seen this on other cloud providers yet, but I have seen it on local loads of linux using various other versions of them.
Well let me make it even more clear I have seen the /boot/efi/EFI/distro on other cloud servers, but it's usually empty, so there no mount listed in the fstab.
Section 1.5.1 Restricting core dumps
################################################
#### 1.5.1 Ensure core dumps are restricted ####
################################################
function core_dumps() {
{
start_spinner 'Restricting Core Dumps...'
echo ""
xargs -n 1 cp -v /etc/security/limits.conf <<<"${BACKUP} /etc/security/limits.conf.bak"
echo '* hard core 0' >> /etc/security/limits.conf
stop_spinner $?
} | tee -a $LOG
}
This just adds "hard core 0" to the limits.conf file.
Section 1.5.3 Ensure ASLR is Enabled
###########################################################################
#### 1.5.3 Ensure address space layout randomization (ASLR) is enabled ####
###########################################################################
function sysctl_conf() {
{
start_spinner 'Configuring Sysctl and Tuning Kernel Parameters...'
echo ""
xargs -n 1 cp -v /etc/sysctl.conf <<< "${BACKUP} /etc/sysctl.conf.bak"
no_show << "EOF" > /etc/sysctl.conf
##################################################################################################
#### Hardened SysCtl Configuration File edited to match CIS level 1 requirements ####
#### for questions or changles please contact Phil Connor contact@mylinux.work ####
##################################################################################################
#### Controls the System Request debugging functionality of the kernel
kernel.sysrq = 0
#### Controls whether core dumps will append the PID to the core filename.
#### Useful for debugging multi-threaded applications.
kernel.core_uses_pid = 1
##################################
#### GENERAL SECURITY OPTIONS ####
##################################
#### Automatically Reboot Server 30 Seconds after a Kernel Panic
vm.panic_on_oom = 1
kernel.panic = 30
kernel.panic_on_oops = 30
#### Enable ExecShield
#kernel.exec-shield = 1
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 1
kernel.yama.ptrace_scope = 1
#### 1.5.3 Ensure address space layout randomization (ASLR) is enabled
kernel.randomize_va_space = 2
#################################
#### COMMUNICATIONS SECURITY ####
#################################
#### 3.1.1 Ensure IP forwarding is disabled
net.ipv4.ip_forward = 0
net.ipv4.conf.all.forwarding = 0
net.ipv4.conf.default.forwarding = 0
net.ipv6.conf.all.forwarding = 0
net.ipv6.conf.default.forwarding = 0
#### 3.1.2 Ensure packet redirect sending is disabled
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
#### 3.2.1 Ensure source routed packets are not accepted
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
#### 3.2.2 Ensure ICMP redirects are not accepted
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
#### 3.2.3 Ensure secure ICMP redirects are not accepted
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
#### 3.2.4 Ensure suspicious packets are logged
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
#### 3.2.5 Ensure broadcast ICMP requests are ignored
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.tcp_timestamps = 0
#### 3.2.6 Ensure bogus ICMP responses are ignored
net.ipv4.icmp_ignore_bogus_error_responses = 1
#### 3.2.7 Ensure Reverse Path Filtering is enabled
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
#### 3.2.8 Ensure TCP SYN Cookies is enabled
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syn_retries = 5
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_max_syn_backlog = 4096
#### 3.3.1 Ensure IPv6 router advertisements are not accepted
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.default.accept_ra = 0
#### 3.3.1.1 Ensure IPv6 router advertisements are not accepted
net.ipv4.conf.all.accept_source_route=0
net.ipv6.conf.all.accept_source_route=0
net.ipv4.conf.default.accept_source_route=0
net.ipv6.conf.default.accept_source_route=0
#### 3.3.2 Ensure IPv6 redirects are not accepted
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
#### 3.3.3 Ensure IPv6 is disabled
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
#### Reduce KeepAlive
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 15
fs.suid_dumpable = 0
#########################
#### Oracle Settings ####
#########################
# oracle-ebs-server-R12-preinstall setting for fs.file-max is 6815744
fs.file-max = 6815744
# oracle-ebs-server-R12-preinstall setting for kernel.sem is '256 32000 100 142'
kernel.sem = 256 32000 100 142
# oracle-ebs-server-R12-preinstall setting for kernel.shmmni is 4096
kernel.shmmni=4096
# oracle-ebs-server-R12-preinstall setting for kernel.shmall is 1073741824 on x86_64
# oracle-ebs-server-R12-preinstall setting for kernel.shmall is 2097152 on i386
kernel.shmall=1073741824
# oracle-ebs-server-R12-preinstall setting for kernel.shmmax is 4398046511104 on x86_64
# oracle-ebs-server-R12-preinstall setting for kernel.shmmax is 4294967295 on i386
kernel.shmmax=4398046511104
# oracle-ebs-server-R12-preinstall setting for kernel.panic_on_oops is 1
kernel.panic_on_oops=1
# oracle-ebs-server-R12-preinstall setting for kernel.msgmax is 8192
kernel.msgmax = 8192
# oracle-ebs-server-R12-preinstall setting for kernel.msgmni is 2878
kernel.msgmni=2878
# oracle-ebs-server-R12-preinstall setting for kernel.msgmnb is 65535
kernel.msgmnb=65535
# oracle-ebs-server-R12-preinstall setting for net.core.rmem_default is 262144
net.core.rmem_default=262144
# oracle-ebs-server-R12-preinstall setting for net.core.rmem_max is 4194304
net.core.rmem_max=4194304
# oracle-ebs-server-R12-preinstall setting for net.core.wmem_default is 262144
net.core.wmem_default=262144
# oracle-ebs-server-R12-preinstall setting for net.core.wmem_max is 1048576
net.core.wmem_max=1048576
# oracle-ebs-server-R12-preinstall setting for fs.aio-max-nr is 1048576
fs.aio-max-nr = 1048576
# oracle-ebs-server-R12-preinstall setting for net.ipv4.ip_local_port_range is 9000 65500
net.ipv4.ip_local_port_range = 9000 65500
EOF
sysctl -p
stop_spinner $?
} | tee -a $LOG
}
This is the sysctl.conf config that I have refined over time, the servers perform fairly well with these settings, I left the "Oracle Settings" in there and they can be safely removed if you want.
Section 1.5.4 Ensure prelink is disabled
f##########################################
#### 1.5.4 Ensure prelink is disabled ####
##########################################
function pre_link() {
{
start_spinner 'Disabling and removing Prelink...'
echo ""
if [ -f /usr/sbin/prelink ]; then
prelink -ua
${PAKMGR} remove prelink
fi
stop_spinner $?
} | tee -a $LOG
}
Simply put if prelink is enabled of found disable and remove it.
Section 1.6.1.4 Ensure SE Troubleshoot is not installed
########################################################
#### 1.6.1.4 Ensure SETroubleshoot is not installed ####
########################################################
function se_troubleshoot_mcs() {
{
start_spinner 'Removing SE Troubleshoot and MCS Translation Service...'
echo ""
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle || ${OS} = rocky || ${OS} = alma ]]; then
if [ -f /usr/bin/setroubleshoot ]; then
${PAKMGR} remove setroubleshoot
fi
fi
#### 1.6.1.5 Ensure the MCS Translation Service (mcstrans) is not installed ####
if [ "${OS}" = ubuntu ]; then
systemctl list-units --type=service --all | grep mcstrans
if ! 1; then
${PAKMGR} remove policycoreutils
fi
else
systemctl list-units --type=service --all | grep mcstrans
if ! 1; then
${PAKMGR} remove mcstrans
fi
fi
stop_spinner $?
} | tee -a $LOG
}
Just checking for and removing SE Troubleshoot, I also have the mctrans check/removal in here.
Section 1.6.1.6 Ensure no Unconfined Daemons Exist
######################################################
#### 1.6.1.6 Ensure no unconfigured daemons exist ####
######################################################
function unconf_daemons() {
{
start_spinner 'Ensuring no unconfigered daemons exist...'
echo ""
process=$(ps -eZ)
echo "${process}" | grep -E "initrc" | grep -Evw "tr|ps|grep|bash|awk" | tr ':' ' ' | awk '{ print $NF }'
stop_spinner $?
} | tee -a $LOG
}
this check is designed to find all unconfined things that are running, what this means is all services a confined under selinux these are considered undefined domains, these include scripts that you may use and put in the /usr/local/bin/ and only include scripts that you run as a service or a loop.
the problem with this check is on new spin ups you've not loaded any of those so this will not detect anything, in fact you will not have any idea about this until Nessus alerts you. Just remember to confine your scripts with selinux to avoid any future issues.
Section 1.6.2 Ensure SELinix is Installed
###########################################
#### 1.6.2 Ensure SELinux is installed ####
###########################################
function se_linux() {
{
start_spinner 'Ensuring SELinux is installed...'
echo ""
if [ "${OS}" = ubuntu ]; then
${PAKMGR} install libselinux1
else
if ! rpm -qa libselinux; then
${PAKMGR} install libselinux
fi
fi
stop_spinner $?
} | tee -a $LOG
}
This again explains itself....
Section 1.7.1.1 Ensure the message of the day is configured
##################################################################
#### 1.7.1.1 Ensure message of the day is configured properly ####
##################################################################
function banners() {
{
start_spinner 'Configuring all Message Banners...'
echo ""
if [ "${OS}" = ubuntu ]; then
chmod -x /etc/update-motd.d/*
touch /etc/motd
else
xargs -n 1 cp -v /etc/motd <<< "${BACKUP} /etc/motd.bak"
fi
echo " All activities performed on this system will be monitored." > /etc/motd
#### 1.7.1.2 Ensure local login warning banner is configured properly ####
xargs -n 1 cp -v /etc/issue <<< "${BACKUP} /etc/issue.bak"
echo " All activities performed on this system will be monitored." > /etc/issue
#### 1.7.1.3 Ensure remote login warning banner is configured properly ####
xargs -n 1 cp -v /etc/issue.net <<< "${BACKUP} /etc/issue.net.bak"
echo " All activities performed on this system will be monitored." > /etc/issue.net
#### 1.7.1.4 Ensure permissions on /etc/motd ore configured ####
chmod 644 /etc/motd
chown root.root /etc/motd
#### 1.7.1.5 Ensure permissions on /etc/issue are configured ####
chmod 644 /etc/issue
chown root.root /etc/issue
#### 1.7.1.6 Ensure permissions on /etc/issue.net are configured ####
chmod 644 /etc/issue.net
chown root.root /etc/issue.net
stop_spinner $?
} | tee -a $LOG
}
The MOTD - Nessus does not allow for a very long motd so if you have one it will ding you on it and issue and issue.net since it expects all of those to be the same,
I have a banner work around that I use on all the servers that I maintain which doesn't get dinged by Nessus and it shows me the info I need as well as a long message for the users that ssh in to the boxes, you will see it a little later in this script. I also added some color to it with lolcat to catch the users attn.
Here is an example of it enlarged
Section 1.8 Ensure Updates, Patches and Security Packages are Installed
#####################################################################################
#### 1.8 ensure updates, patches, and additional security software are installed ####
#####################################################################################
function update_security() {
{
start_spinner 'Checking and Installing Security Updates...'
echo ""
if [ "${OS}" = ubuntu ]; then
${PAKMGR} autoremove
${PAKMGR} update
"${PAKMGR} install -y --only-upgrade $(apt-get --just-print upgrade | awk 'tolower($4) ~ /.*security.*/ || tolower($5) ~ /.*security.*/ {print $2}' | sort | uniq)"
else
${PAKMGR} clean all
${PAKMGR} check-update --security
${PAKMGR} update --security
fi
stop_spinner $?
} | tee -a $LOG
}
This checks and updates just the security packages nothing else
Section 2.1 Ensure the Inet Service are Disabled
#############################
#### 2.1 inetd Services ####
############################
function inet_service() {
{
start_spinner 'Disabling Unused/Unsecure inetd Services...'
echo ""
#### 2.1.1 Ensure chargen services are not enabled ####
if [ "${OS}" = ubuntu ]; then
grep -R "^chargen" /etc/inetd.*
if ! 2; then
systemctl stop chargen
systemctl disable chargen
fi
else
systemctl is-enabled chargen-dgram
if ! 1; then
systemctl stop chargen-dgram
systemctl disable chargen-dgram
fi
systemctl is-enabled chargen-stream
if ! 1; then
systemctl stop chargen-stream
systemctl disable chargen-stream
fi
fi
#### 2.1.2 Ensure daytime services are not enabled ####
if [ "${OS}" = ubuntu ]; then
grep -R "^daytime" /etc/inetd.*
if ! 2; then
systemctl stop daytime
systemctl disable daytime
fi
else
systemctl is-enabled daytime-dgram
if ! 1; then
systemctl stop daytime-dgram
systemctl disable daytime-dgram
fi
systemctl is-enabled daytime-stream
if ! 1; then
systemctl stop daytime-stream
systemctl disable daytime-stream
fi
fi
#### 2.1.3 Ensure discard services are not enabled ####
if [ "${OS}" = ubuntu ]; then
grep -R "^discard" /etc/inetd.*
if ! 2; then
systemctl stop discard
systemctl disable discard
fi
else
systemctl is-enabled discard-dgram
if ! 1; then
systemctl stop discard-dgram
systemctl disable discard-dgram
fi
systemctl is-enabled discard-stream
if ! 1; then
systemctl stop discard-stream
systemctl disable discard-stream
fi
fi
#### 2.1.4 Ensure echo services are not Enabled ####
if [ "${OS}" = ubuntu ]; then
grep -R "^echo" /etc/inetd.*
if ! 2; then
systemctl stop echo
systemctl disable echo
fi
else
systemctl is-enabled echo-stream
if ! 1; then
systemctl stop echo-stream
systemctl disable echo-stream
fi
fi
#### 2.1.5 Ensure time services are not enabled ####
if [ "${OS}" = ubuntu ]; then
grep -R "^time" /etc/inetd.*
if ! 2; then
systemctl stop time
systemctl disable time
fi
else
systemctl is-enabled time-dgram
if ! 1; then
systemctl stop time-dgram
systemctl disable time-dgram
fi
systemctl is-enabled time-stream
if ! 1; then
systemctl stop time-stream
systemctl disable time-stream
fi
fi
#### 2.1.6 Ensure rsh server is not enabled Ubuntu ####
if [ "${OS}" = ubuntu ]; then
grep -R "^shell" /etc/inetd.*
if ! 2; then
systemctl stop shell
systemctl disable shell
fi
grep -R "^login" /etc/inetd.*
if ! 2; then
systemctl stop login
systemctl disable login
fi
grep -R "^exec" /etc/inetd.*
if ! 2; then
systemctl stop exec
systemctl disable exec
fi
fi
#### 2.1.6 Ensure tftp server is not enabled Others ####
systemctl is-enabled tftp
if ! 1; then
systemctl stop tftp
systemctl disable tftp
fi
#### 2.1.7 Ensure talk server is not enabled Ubuntu ####
if [ "${OS}" = ubuntu ]; then
grep -R "^talk" /etc/inetd.*
if ! 2; then
systemctl stop talk
systemctl disable talk
fi
grep -R "^ntalk" /etc/inetd.*
if ! 2; then
systemctl stop ntalk
systemctl disable ntalk
fi
fi
#### 2.1.9 Ensure tftp server is not enabled Ubuntu ####
if [ "${OS}" = ubuntu ]; then
grep -R "^tftp" /etc/inetd.*
if ! 2; then
systemctl stop tftp
systemctl disable tftp
fi
fi
#### 2.1.8 Ensure telnet server is not enabled Ubuntu ####
if [ "${OS}" = ubuntu ]; then
grep -R "^telnet" /etc/inetd.*
if ! 2; then
systemctl stop telnet
systemctl disable telnet
fi
fi
#### 2.1.10 Ensure xinetd is not enabled All ####
systemctl is-enabled xinetd
if ! 1; then
systemctl stop xinetd
systemctl disable xinetd
fi
stop_spinner $?
} | tee -a $LOG
}
Disabling all insecure inet services
Section 2.2.1.1 Ensure Time Synchronization is in Use
#######################################################
#### 2.2.1.1 Ensure time synchronization is in use ####
#######################################################
#### 2.2.1.2 Ensure ntp is configured ####
function ntp_config() {
{
start_spinner 'Configuring NTP Service...'
echo ""
if [ "${OS}" = ubuntu ]; then
DEBIAN_FRONTEND=noninteractive ${PAKMGR} install ntp
else
${PAKMGR} install ntp
fi
if [ "${OS}" = centos ]; then
var1=${OS}
elif [ "${OS}" = ubuntu ]; then
var1=${OS}
else
var1=rhel
fi
if [ "${OS}" = centos ]; then
sed -i 's/OPTIONS="-g"/OPTIONS="-u ntp:ntp"/g' /etc/sysconfig/ntpd
if ! grep -qi "server 127.127.1.0" ${NTP_FILE}; then
echo "server 127.127.1.0 #local clock" >> ${NTP_FILE}
echo "fudge 127.127.1.0 stratum 10" >> ${NTP_FILE}
fi
if ! grep -qi "disable monitor" ${NTP_FILE}; then
echo "disable monitor" >> ${NTP_FILE}
fi
systemctl enable --now ntpd
elif [ "${OS}" = ubuntu ]; then
if ! grep -qi "server 127.127.1.0" ${NTP_FILE}; then
echo "server 127.127.1.0 #local clock" >> ${NTP_FILE}
echo "fudge 127.127.1.0 stratum 10" >> ${NTP_FILE}
fi
if ! grep -qi "disable monitor" ${NTP_FILE}; then
echo "disable monitor" >> ${NTP_FILE}
fi
if ! grep -qi "RUNASUSER=ntp" /etc/init.d/ntp; then
echo "RUNASUSER=ntp" >> /etc/init.d/ntp
fi
else
xargs -n 1 cp -v ${NTP_FILE} <<< ""${BACKUP} ${NTP_FILE}.bak""
sed -i 's/restrict default nomodify notrap nopeer noquery/restrict default nomodify notrap nopeer noquery/p' ${NTP_FILE}
sed -i '8 s/restrict default nomodify notrap nopeer noquery/restrict -4 default kod nomodify notrap nopeer noquery/g' ${NTP_FILE}
sed -i '9 s/restrict default nomodify notrap nopeer noquery/restrict -6 default kod nomodify notrap nopeer noquery/g' ${NTP_FILE}
sed -i 's/OPTIONS="-g"/OPTIONS="-u ntp:ntp"/g' /etc/sysconfig/ntpd
if ! grep -qi "server 127.127.1.0" "${NTP_FILE}"; then
echo "server 127.127.1.0 #local clock" >> ${NTP_FILE}
echo "fudge 127.127.1.0 stratum 10" >> ${NTP_FILE}
fi
if ! grep -qi "disable monitor" ${NTP_FILE}; then
echo "disable monitor" >> ${NTP_FILE}
fi
systemctl enable --now ntpd
systemctl restart ntpd
fi
sed -i "s/#server 0.$var1.pool.ntp.org iburst/server 0.$var1.pool.ntp.org iburst/g" ${NTP_FILE}
sed -i "s/#server 1.$var1.pool.ntp.org iburst/server 1.$var1.pool.ntp.org iburst/g" ${NTP_FILE}
sed -i "s/#server 2.$var1.pool.ntp.org iburst/server 2.$var1.pool.ntp.org iburst/g" ${NTP_FILE}
sed -i "s/#server 3.$var1.pool.ntp.org iburst/server 3.$var1.pool.ntp.org iburst/g" ${NTP_FILE}
systemctl enable --now ntp
systemctl enable --now systemd-timesyncd
stop_spinner $?
} | tee -a $LOG
}
#### 2.2.1.3 Ensure chrony is configured ####
function chrony_cfg() {
{
start_spinner 'Configuring Chrony Service...'
echo ""
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle || ${OS} = rocky || ${OS} = alma ]]; then
if [ "${OSVER}" = 8 ] || [ "${OSVER}" = 9 ]; then
${PAKMGR} install chrony ntpstat
fi
elif [ "${OS}" = ubuntu ]; then
DEBIAN_FRONTEND=noninteractive ${PAKMGR} install chrony
else
${PAKMGR} install chrony
fi
if [ "${OS}" = centos ]; then
var1=${OS}
else
var1=rhel
fi
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle || ${OS} = rocky || ${OS} = alma ]]; then
if [ "${OSVER}" = 7 ]; then
if ! grep $var1.pool.ntp.org /etc/chrony.conf; then
echo '#################################################################'
echo '#### Using public servers from the pool.ntp.org project. ####'
echo '#### Added for CIS Level 1 Compatibility for questions ####'
echo '#### Contact Phil Connor contact@mylinux.work ####'
echo '#################################################################'
echo "server 0.$var1.pool.ntp.org iburst"
echo "server 1.$var1.pool.ntp.org iburst"
echo "server 2.$var1.pool.ntp.org iburst"
echo "server 3.$var1.pool.ntp.org iburst"
sed -i "s/#server 0.$var1.pool.ntp.org iburst/server 0.$var1.pool.ntp.org iburst/g" /etc/chrony.conf
sed -i "s/#server 1.$var1.pool.ntp.org iburst/server 1.$var1.pool.ntp.org iburst/g" /etc/chrony.conf
sed -i "s/#server 2.$var1.pool.ntp.org iburst/server 2.$var1.pool.ntp.org iburst/g" /etc/chrony.conf
sed -i "s/#server 3.$var1.pool.ntp.org iburst/server 3.$var1.pool.ntp.org iburst/g" /etc/chrony.conf
sed -i 's/server 169.254.169.254 iburst/#server 169.254.169.254 iburst/g' /etc/chrony.conf
sed -i 's/OPTIONS=""/OPTIONS="-u chrony"/g' /etc/sysconfig/chronyd
fi
fi
fi
if [ "${OSVER}" = 8 ] || [ "${OSVER}" = 9 ]; then
if ! grep $var1.pool.ntp.org /etc/chrony.conf; then
chronyd -q 'server 2.rhel.pool.ntp.org iburst'
sed -i 's/OPTIONS="-F 2"/OPTIONS="-u chrony"/g' /etc/sysconfig/chronyd
chronyc sourcestats -v
fi
systemctl enable --now chronyd
fi
if [ "${OS}" = ubuntu ]; then
if grep -q 'OPTIONS=.*' /etc/sysconfig/chronyd; then
sed -i -E -e 's/\s*-u\s+\w+\s*/ /' -e 's/^([\s]*OPTIONS=["]?[^"]*)("?)/\1 -u chrony\2/' /etc/sysconfig/chronyd
if [ ! -f /etc/sysconfig/chronyd ]; then
touch /etc/sysconfig/chronyd
echo "OPTIONS="-u chrony"" /etc/sysconfig/chronyd
fi
fi
chronyc sourcestats -v
fi
stop_spinner $?
} | tee -a $LOG
}
Configuring NTP and or Chrony services
Section 2.2.2 Ensure X Windows is not installed
#######################################################
#### 2.2.2 Ensure X Window System is not installed ####
#######################################################
function unsecure_services() {
{
start_spinner 'Removing X11 and Disabling Insecure Protocols...'
echo ""
if [ "${OS}" = ubuntu ]; then
${PAKMGR} remove xorg*
${PAKMGR} remove xserver-xorg*
else
${PAKMGR} remove xorg-x11*
fi
a=( "$(systemctl list-units --type=service --all)" )
#### 2.2.3 Ensure Avahi Server is not installed ####
if echo "${a[@]}" | grep avahi-daemon.service; then
systemctl stop avahi-daemon
systemctl disable avahi-daemon
fi
### 2.2.4 Ensure CUPS is not enabled ###
if echo "${a[@]}" | grep cups.service; then
systemctl stop cups
systemctl disable cups
fi
#### 2.2.5 Ensure DHCP Server is not enabled ####
if [ "${OS}" = ubuntu ]; then
if echo "${a[@]}" | grep isc-dhcp-server.service; then
systemctl stop isc-dhcp-server
systemctl disable isc-dhcp-server
fi
else
if echo "${a[@]}" | grep dhcpd.service; then
systemctl stop dhcpd
systemctl disable dhcpd
fi
fi
#### 2.2.6 Ensure LDAP Server is not enabled ####
if echo "${a[@]}" | grep slapd.service; then
systemctl stop slapd
systemctl disable slapd
fi
#### 2.2.7 Ensure NFS and RPC are not enabled ####
if [ "${OS}" = ubuntu ]; then
if echo "${a[@]}" | grep nfs-kernel-server.service; then
systemctl stop nfs-kernel-server
systemctl disable nfs-kernel-server
fi
else
if echo "${a[@]}" | grep nfs-server.service; then
systemctl stop nfs-server
systemctl disable nfs-server
fi
if echo "${a[@]}" | grep nfs.service; then
systemctl stop nfs
systemctl disable nfs
fi
fi
if echo "${a[@]}" | grep rpcbind.service; then
systemctl stop rpcbind
systemctl disable rpcbind
fi
#### 2.2.8 Ensure DNS Server is not enabled ####
if echo "${a[@]}" | grep named.service; then
systemctl stop named
systemctl disable named
fi
if [ "${OS}" = ubuntu ]; then
if echo "${a[@]}" | grep bind9.service; then
systemctl stop bind9
systemctl disable bind9
fi
fi
#### 2.2.9 Ensure FTP Server is not enabled ####
if echo "${a[@]}" | grep vsftpd.service; then
systemctl stop vsftpd
systemctl disable vsftpd
fi
#### 2.2.10 Ensure HTTP Server is not enabled ####
if [ "${OS}" = ubuntu ]; then
if echo "${a[@]}" | grep apache2.service; then
systemctl stop apache2
systemctl disable apache2
fi
else
if echo "${a[@]}" | grep httpd.service; then
systemctl stop httpd
systemctl disable httpd
fi
fi
#### 2.2.11 Ensure IMAP and POP3 server are not enabled ####
if echo "${a[@]}" | grep dovecot.service; then
systemctl stop dovecot
systemctl disable dovecot
fi
#### 2.2.12 Ensure Samba is not enabled ####
if echo "${a[@]}" | grep smb.service; then
systemctl stop smb
systemctl disable smb
fi
#### 2.2.13 Ensure HTTP Proxy Server is not enabled ####
if echo "${a[@]}" | grep squid.service; then
systemctl stop squid
systemctl disable squid
fi
#### 2.2.14 Ensure SNMP Server is not enabled ####
if echo "${a[@]}" | grep snmpd.service; then
systemctl stop snmpd
systemctl disable snmpd
fi
stop_spinner $?
} | tee -a $LOG
}
Removing and disabling additional insecure services
Section 2.2.15 Ensure Postfix Only Delivers Locally
#############################################################################
#### 2.2.15 Ensure mail transfer agent is configured for local-only mode ####
#############################################################################
function mail_config() {
{
start_spinner 'Configuring Postfix MTA...'
echo ""
if [ "${OS}" = ubuntu ]; then
debconf-set-selections <<< ""postfix postfix/mailname string "${HOSTNAME}"""
debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'"
DEBIAN_FRONTEND=noninteractive ${PAKMGR} install postfix --assume-yes
sed -i 's/inet_interfaces = all/inet_interfaces = localhost/g' /etc/postfix/main.cf
else
${PAKMGR} install postfix
sed -i 's/inet_interfaces = localhost/inet_interfaces = loopback-only/g' /etc/postfix/main.cf
fi
# shellcheck disable=SC2016
sed -i 's/#smtpd_banner = $myhostname ESMTP $mail_name/smtpd_banner = $myhostname ESMTP/g' /etc/postfix/main.cf
# shellcheck disable=SC2016
sed -i 's/smtpd_banner = $myhostname ESMTP ($mail_version)/#smtpd_banner = $myhostname ESMTP $mail_name ($mail_version)/g' /etc/postfix/main.cf
if ! grep -qi "mailbox_size_limit" /etc/postfix/main.cf; then
echo "mailbox_size_limit = 0" >> /etc/postfix/main.cf
fi
postconf -e message_size_limit=0
postconf -e mailbox_size_limit = 0
systemctl enable --now postfix
stop_spinner $?
} | tee -a $LOG
}
This installs and configures Postfix to deliver all mail locally only
Section 2.2.x Disabling Additional inet Services
################################################
#### 2.2.x Disable Additional inet Services ####
################################################
function addon_inet_services() {
{
start_spinner 'Disabling Additional Unsecure Services...'
echo ""
a=( "$(systemctl list-units --type=service --all)" )
### 2.2.16 Ensure NIS Server is not enabled ###
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle || ${OS} = rocky || ${OS} = alma ]]; then
if echo "${a[@]}" | grep ypserv.service; then
systemctl stop ypserv
systemctl disable ypserv
fi
### 2.2.16 Ensure rsync service is not enabled Ubuntu ###
elif [ "${OS}" = ubuntu ]; then
if echo "${a[@]}" | grep rsync.service; then
systemctl stop rsync
systemctl disable rsync
fi
fi
### 2.1.17 Ensure rsh server is not enabled ###
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle ]]; then
if echo "${a[@]}" | grep rsh.socket.service; then
systemctl stop rsh.socket
systemctl disable rsh.socket
fi
if echo "${a[@]}" | grep rlogin.socket.service; then
systemctl stop rlogin.socket
systemctl disable rlogin.socket
fi
if echo "${a[@]}" | grep rexec.socket.service; then
systemctl stop rexec.socket
systemctl disable rexec.socket
fi
### 2.2.17 Ensure NIS Server is not enabled Ubuntu ###
elif [ "${OS}" = ubuntu ]; then
if echo "${a[@]}" | grep nis.service; then
systemctl stop nis
systemctl disable nis
fi
fi
### 2.2.18 Ensure talk server is not enabled ###
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle ]]; then
if echo "${a[@]}" | grep ntalk.service; then
systemctl stop ntalk
systemctl disable ntalk
fi
### 2.2.19 Ensure telnet server is not enabled ###
if echo "${a[@]}" | grep telnet.socket.service; then
systemctl stop telnet.socket
systemctl disable telnet-socket
fi
### 2.2.20 Ensure tftp server is not enabled ###
if echo "${a[@]}" | grep tftp.socket.service; then
systemctl stop tftp.socket
systemctl disable tftp-socket
fi
### 2.2.21 Ensure rsync service is not enabled ###
if echo "${a[@]}" | grep rsyncd.service; then
systemctl stop rsyncd
systemctl disable rsyncd
fi
fi
stop_spinner $?
} | tee -a $LOG
}
For some reason the manual breaks up a lot of the process. I tried to write this script to match the flow of the manual the best I could so that finding where something was not working would be easier to track down.
Section 2.3 Ensure Insecure Service Clients are not Installed
###############################################################
#### 2.3 Ensure Insecure Service Clients are not Installed ####
###############################################################
function service_clients() {
{
start_spinner 'Removing Insecure Service Clients...'
echo ""
a=( "$(systemctl list-units --type=service --all)" )
#### 2.3.1 Ensure NIS Client is not installed ####
if [ "${OS}" = ubuntu ]; then
if echo "${a[@]}" | grep nis.service; then
${PAKMGR} remove nis
fi
else
if echo "${a[@]}" | grep ypbind.service; then
${PAKMGR} remove ypbind
fi
fi
#### 2.3.2 Ensure rsh client is not installed ####
if [ "${OS}" = ubuntu ]; then
if echo "${a[@]}" | grep rsh-client.service; then
${PAKMGR} remove rsh-client rsh-redone-client
fi
else
if echo "${a[@]}" | grep rsh.service; then
${PAKMGR} remove rsh
fi
fi
#### 2.3.3 Ensure talk client is not installed ####
if echo "${a[@]}" | grep talk.service; then
${PAKMGR} remove talk
fi
#### 2.3.4 Ensure telnet client is not installed ####
if echo "${a[@]}" | grep telnet.service; then
${PAKMGR} remove telnet
fi
#### 2.3.5 Ensure LDAP client is not installed ####
if [ "${OS}" = ubuntu ]; then
if echo "${a[@]}" | grep libnss-ldap.service; then
${PAKMGR} remove libnss-ldap
fi
if echo "${a[@]}" | grep libpam-ldap.service; then
${PAKMGR} remove libpam-ldap
fi
if echo "${a[@]}" | grep ldap-utils.service; then
${PAKMGR} remove ldap-utils
fi
else
if echo "${a[@]}" | grep openldap-clients.service; then
${PAKMGR} remove openldap-clients
fi
fi
stop_spinner $?
} | tee -a $LOG
}
Section 3.4 TCP Wrappers
##########################
#### 3.4 TCP Wrappers ####
##########################
function tcp_wrappers() {
{
start_spinner 'Configuring TCP Wrappers...'
echo ""
#### 3.4.1 Ensure TCP Wrappers is installed ####
if [ "${OS}" = ubuntu ]; then
${PAKMGR} install tcpd
else
${PAKMGR} list | grep tcp_wrappers
if ! 1; then
${PAKMGR} install tcp_wrappers
fi
fi
#### 3.4.2 Ensure /etc/hosts.allow is configured ####
echo ALL:"${VLANIP}" > /etc/hosts.allow
#### 3.4.3 Ensure /etc/hosts.deny is configured ####
echo "ALL:ALL" >> /etc/hosts.deny
#### 3.4.4 Ensure permissions on /etc/hosts.allow are configured ####
chown root.root /etc/hosts.allow
chmod 644 /etc/hosts.allow
#### 3.4.5 Ensure permissions on /etc/hosts.deny are configured ####
chown root.root /etc/hosts.deny
chmod 644 /etc/hosts.deny
stop_spinner $?
}
}
This is no longer supported in Redhat based distro's beyond Version 7
Section 3.5 Uncommon Network Protocals
########################################
#### 3.5 Uncommon Network Protocols ####
########################################
function uncommon_protocols() {
{
start_spinner 'Disabling Uncommon Network Protocols...'
echo ""
MODPRO="/etc/modprobe.d/cis.conf"
#### 3.5.1 Ensure DCCP is disabled ####
echo "install dccp /bin/true" >> ${MODPRO}
lsmod | grep -qi dccp
if ! 1; then
rmmod dccp
fi
#### 3.5.2 Ensure SCTP is disabled ####
echo "install sctp /bin/true" >> ${MODPRO}
lsmod | grep -qi sctp
if ! 1; then
rmmod sctp
fi
#### 3.5.3 ensure RDS is disabled ####
echo "install rds /bin/true" >> ${MODPRO}
lsmod | grep -qi rds
if ! 1; then
rmmod rds
fi
#### 3.5.4 Ensure TIPC is disabled ####
echo "install tipc /bin/true" >> ${MODPRO}
lsmod | grep -qi tipc
if ! 1; then
rmmod tipc
fi
stop_spinner $?
} | tee -a $LOG
}
Section 3.6 Firewall Configuration
########################################
#### 3.6 Firewall Configuration AWS ####
########################################
function iptables_config() {
{
start_spinner 'Configuring IP Tables...'
echo ""
### 3.6.1 Ensure iptables is installed ###
if [ "${OS}" = ubuntu ]; then
ufw --force disable
debconf-set-selections <<< "iptables-persistent iptables-persistent/autosave_v4 boolean true"
debconf-set-selections <<< "iptables-persistent iptables-persistent/autosave_v6 boolean true"
DEBIAN_FRONTEND=noninteractive ${PAKMGR} install iptables
DEBIAN_FRONTEND=noninteractive ${PAKMGR} install iptables-persistent --assume-yes
service netfilter-persistent start
service netfilter-persistent save
else
systemctl stop firewalld.service
systemctl mask firewalld.service
systemctl daemon-reload
${PAKMGR} install iptables-utils iptables-services
fi
#### 3.6.2 Ensure default deny firewall policy ####
#### Configure IPv4 ####
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle || ${OS} = rocky || ${OS} = alma ]]; then
systemctl enable --now iptables
cp $IPTBL $BACKUP
mv -f ${IPTBL} ${IPTBL}.bak
touch ${IPTBL}
fi
# Flush Iptables rules
iptables -F
# Forcing SYN packets check
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
# Forcing Fragments packets check
iptables -A INPUT -f -j DROP
# Dropping malformed XMAS packets
iptables -A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
# Drop all NULL packets
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
# Limiting pings to 1 per second
iptables -N PACKET
iptables -A DEFAULT_RULES -p icmp -m limit --limit 3/sec --limit-burst 25 -j ACCEPT
# Setup Connection Tracking
iptables -N STATE_TRACK
iptables -A STATE_TRACK -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A STATE_TRACK -m state --state INVALID -j DROP
# Discouraging Port Scanning
iptables -N PORTSCAN
iptables -A PORTSCAN -p tcp --tcp-flags ACK,FIN FIN -j DROP
iptables -A PORTSCAN -p tcp --tcp-flags ACK,PSH PSH -j DROP
iptables -A PORTSCAN -p tcp --tcp-flags ACK,URG URG -j DROP
iptables -A PORTSCAN -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
iptables -A PORTSCAN -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
iptables -A PORTSCAN -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
iptables -A PORTSCAN -p tcp --tcp-flags ALL ALL -j DROP
iptables -A PORTSCAN -p tcp --tcp-flags ALL NONE -j DROP
iptables -A PORTSCAN -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
iptables -A PORTSCAN -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP
iptables -A PORTSCAN -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
iptables -N COMMON
iptables -A COMMON -j STATE_TRACK
iptables -A COMMON -j PORTSCAN
iptables -A COMMON -j PACKET
iptables -A INPUT -j COMMON
iptables -A OUTPUT -j COMMON
iptables -A FORWARD -j COMMON
iptables -A FORWARD -j PACKET
# Ensure loopback traffic is configured
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -s 127.0.0.0/8 -j DROP
iptables -A OUTPUT -o lo -j ACCEPT
# Ensure outbound and established connections are configured
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -j LOG --log-prefix "iptables_output "
# Add Network Connection IP
iptables -A INPUT -s "${FIREIP}" -d "${FIREIP}" -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -s "${FIREIP}" -d "${FIREIP}" -m state --state NEW,ESTABLISHED -j ACCEPT
# Open inbound ssh(22) connections and linit connects to 10 every 10 seconds
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j ACCEPT
# Default deny Firewall policy
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
for port in "${TCPPORTS[@]}"
do
echo "Opening TCP Port $port"
/sbin/iptables -A INPUT -p tcp -m tcp --dport "$port" -j ACCEPT
done
# Open UDP Ports
for port in "${UDPPORTS[@]}"
do
echo "Opening UDP Port $port"
/sbin/iptables -A INPUT -p udp -m udp --dport "$port" -j ACCEPT
done
# Save and Start IPTables
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle || ${OS} = rocky || ${OS} = alma ]]; then
iptables-save > ${IPTBL}
systemctl restart iptables
elif [ "${OS}" = ubuntu ]; then
iptables-save > ${IPTBLUB}
sed -i '/:ufw-/d' ${IPTBLUB}
sed -i '/-j ufw-/d' ${IPTBLUB}
iptables-restore < ${IPTBLUB}
fi
# Configure IPv6 Firewall Ensure Default Deny Policy
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle || ${OS} = rocky || ${OS} = alma ]]; then
cp $IPTBL $BACKUP
mv -f $IP6TBL $IP6TBL.bak
touch $IP6TBL
systemctl enable ip6tables
fi
# Flush Iptables rules
ip6tables -F
# Default deny Firewall policy
ip6tables -P INPUT DROP
ip6tables -P OUTPUT DROP
ip6tables -P FORWARD DROP
ip6tables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
# Forcing Fragments packets check
ip6tables -A INPUT -f -j DROP
# Dropping malformed XMAS packets
ip6tables -A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
# Drop all NULL packets
ip6tables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
# Limiting pings to 1 per second
ip6tables -N PACKET
ip6tables -A DEFAULT_RULES -p icmp -m limit --limit 3/sec --limit-burst 25 -j ACCEPT
# Setup Connection Tracking
ip6tables -N STATE_TRACK
ip6tables -A STATE_TRACK -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -A STATE_TRACK -m state --state INVALID -j DROP
# Discouraging Port Scanning
ip6tables -N PORTSCAN
ip6tables -A PORTSCAN -p tcp --tcp-flags ACK,FIN FIN -j DROP
ip6tables -A PORTSCAN -p tcp --tcp-flags ACK,PSH PSH -j DROP
ip6tables -A PORTSCAN -p tcp --tcp-flags ACK,URG URG -j DROP
ip6tables -A PORTSCAN -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
ip6tables -A PORTSCAN -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
ip6tables -A PORTSCAN -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
ip6tables -A PORTSCAN -p tcp --tcp-flags ALL ALL -j DROP
ip6tables -A PORTSCAN -p tcp --tcp-flags ALL NONE -j DROP
ip6tables -A PORTSCAN -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
ip6tables -A PORTSCAN -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP
ip6tables -A PORTSCAN -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
ip6tables -N COMMON
ip6tables -A COMMON -j STATE_TRACK
ip6tables -A COMMON -j PORTSCAN
ip6tables -A COMMON -j PACKET
ip6tables -A INPUT -j COMMON
ip6tables -A OUTPUT -j COMMON
ip6tables -A FORWARD -j COMMON
ip6tables -A FORWARD -j PACKET
# Ensure loopback traffic is configured
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT -s 127.0.0.0/8 -j DROP
ip6tables -A OUTPUT -o lo -j ACCEPT
# Ensure outbound and established connections are configured
ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -A INPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
ip6tables -A INPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
ip6tables -A INPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
ip6tables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
ip6tables -A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
ip6tables -A OUTPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
ip6tables -A OUTPUT -j LOG --log-prefix "iptables_output "
for port in "${TCP6PORTS[@]}"
do
echo "Opening TCP Port $port"
ip6tables -A INPUT -p tcp -m tcp --dport "$port" -j ACCEPT
done
# Open UDP Ports
for port in "${UDP6PORTS[@]}"
do
echo "Opening UDP Port $port"
ip6tables -A INPUT -p udp -m udp --dport "$port" -j ACCEPT
done
# Save and Start IPTables
if [[ ${OS} = ubuntu ]]; then
ip6tables-save > ${IP6TBLUB}
sed -i '/:ufw6-/d' ${IP6TBLUB}
sed -i '/-j ufw6-/d' ${IPTBLUB}
ip6tables-restore < ${IP6TBLUB}
else
ip6tables-save > ${IP6TBL}
systemctl restart ip6tables
fi
stop_spinner $?
} | tee -a $LOG
}
Additional Cloud Provider Required Rules....
##################################################
#### 3.6a Addional Firewall Configuration AWS ####
##################################################
function iptables_aws() {
{
start_spinner 'Adding AWS Required Rules to IP Tables...'
echo ""
iptables -t nat -A PREROUTING -p tcp -d 169.254.170.2 --dport 80 -j DNAT --to-destination 127.0.0.1:51679
iptables -t nat -A OUTPUT -d 169.254.170.2 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 51679
iptables-save > /etc/sysconfig/iptables
systemctl restart iptables
stop_spinner $?
} | tee -a $LOG
}
##################################################
#### 3.6b Addional Firewall Configuration OCI ####
##################################################
function oci_iptables() {
{
start_spinner 'Adding OCI Required Rules to IP Tables...'
echo ""
iptables -A OUTPUT -d 169.254.0.0/16 -m state --state NEW,ESTABLISHED -p tcp -m tcp -j REJECT --reject-with tcp-reset -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.0.0/16 -m state --state NEW,ESTABLISHED -p udp -m udp -j REJECT -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.0.2/32 -m state --state NEW,ESTABLISHED -p tcp -m tcp --dport 80 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.0.2/32 -m state --state NEW,ESTABLISHED -p tcp -m owner --uid-owner root -m tcp --dport 3260 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.0.3/32 -m state --state NEW,ESTABLISHED -p tcp -m owner --uid-owner root -m tcp --dport 80 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.0.4/32 -m state --state NEW,ESTABLISHED -p tcp -m tcp --dport 80 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.2.0/24 -m state --state NEW,ESTABLISHED -p tcp -m owner --uid-owner root -m tcp --dport 3260 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.4.0/24 -m state --state NEW,ESTABLISHED -p tcp -m owner --uid-owner root -m tcp --dport 3260 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.5.0/24 -m state --state NEW,ESTABLISHED -p tcp -m owner --uid-owner root -m tcp --dport 3260 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.169.254/32 -m state --state NEW,ESTABLISHED -p tcp -m tcp --dport 53 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.169.254/32 -m state --state NEW,ESTABLISHED -p udp -m udp --dport 53 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.169.254/32 -m state --state NEW,ESTABLISHED -p udp -m udp --dport 67 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.169.254/32 -m state --state NEW,ESTABLISHED -p udp -m udp --dport 69 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.169.254/32 -m state --state NEW,ESTABLISHED -p udp -m udp --dport 80 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
iptables -A OUTPUT -d 169.254.169.254/32 -m state --state NEW,ESTABLISHED -p udp -m udp --dport 123 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
# Save and Start IPTables
if [ "${OS}" = ubuntu ]; then
iptables-save > ${IPTBLUB}
sed -i '/:ufw-/d' ${IPTBLUB}
sed -i '/-j ufw-/d' ${IPTBLUB}
iptables-restore < ${IPTBLUB}
else
iptables-save > ${IPTBL}
systemctl restart iptables
fi
stop_spinner $?
} | tee -a $LOG
}
Section 4.1 Configure System Accounting
#########################################
#### 4.1 Configure System Accounting ####
#########################################
function auditd_accounting() {
{
start_spinner 'Configuring Auditd Service...'
echo ""
#### 4.1.1.1 Ensure audit log storage size is configured ####
#### !!! Our current default configuration is 8MB !!! ####
#### 4.1.1.2 Ensure system is disabled when audit logs are full ####
if [ "${OS}" = ubuntu ]; then
debconf-set-selections <<< ""postfix postfix/mailname string "${HOSTNAME}"""
debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'"
DEBIAN_FRONTEND=noninteractive ${PAKMGR} install auditd --assume-yes
else
${PAKMGR} install audit
fi
xargs -n 1 cp -v /etc/audit/auditd.conf <<< ""${BACKUP} /etc/audit/auditd.conf.bak""
### 4.1.1.3 Ensure audit logs are not automaticlly deleted ###
sed -i 's/^space_left_action.*$/space_left_action = email/' /etc/audit/auditd.conf
sed -i 's/^action_mail_acct.*$/action_mail_acct = root/' /etc/audit/auditd.conf
sed -i 's/^admin_space_left_action.*$/admin_space_left_action = halt/' /etc/audit/auditd.conf
# shellcheck disable=SC2086
sed -i ""s/max_log_file_action = ROTATE/max_log_file_action = \"${MAXLOGS}\"/g"" /etc/audit/auditd.conf
### 4.1.2 Ensure auditd service is enabled ####
service auditd reload
if ! systemctl is-enabled auditd; then
systemctl enable --now auditd
fi
### 4.1.3 Ensure auditing for processes that start prior to auditd is enabled"
xargs -n 1 cp -v /etc/default/grub <<< ""${BACKUP} /etc/default/grub.bak""
if ! grep "audit=1" /etc/default/grub; then
sed -i '/^GRUB_CMDLINE_LINUX=/ s/\(\"[^\"]*\)$/ audit=1 &/' /etc/default/grub
fi
if [ "${OS}" = ubuntu ]; then
grub-mkconfig -o ${BACKUP}/grub.cfg
else
grub2-mkconfig -o ${BACKUP}/grub.cfg
fi
if [[ ${OS} = redhat || ${OS} = oracle || ${OS} = rocky || ${OS} = alma ]]; then
cp ${BACKUP}/grub.cfg ${GRUBCFGRH}
cp ${BACKUP}/grub.cfg ${GRUBCFG}
elif [ "${OS}" = ubuntu ]; then
cp ${BACKUP}/grub.cfg ${GRUBCFGUB}
elif [ "${OS}" = centos ]; then
cp ${BACKUP}/grub.cfg ${GRUBCFGCE}
cp ${BACKUP}/grub.cfg ${GRUBCFG}
fi
if ! dmesg | grep '[NX|DX]*Execute Disable'; then
echo 0 > /proc/sys/kernel/exec-shield
fi
### 4.1.4 Ensure events that modify date and time information are collected ###
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle || ${OS} = rocky || ${OS} = alma ]]; then
sed -i 's/RefuseManualStop=yes/RefuseManualStop=no/g' /lib/systemd/system/auditd.service
systemctl daemon-reload
fi
xargs -n 1 cp -v /etc/audit/rules.d/audit.rules <<< ""${BACKUP} /etc/audit/rules.d/audit.rules.bak""
sed -i 's/RefuseManualStop=yes/RefuseManualStop=no/g' /lib/systemd/system/auditd.service
systemctl daemon-reload
{
echo '##################################################################################################'
echo '#### Audit Rules File edited to match CIS level 1 requirements ####'
echo '#### for questions or changes please contact Phil Connor contact@mylinux.work ####'
echo '##################################################################################################'
echo ''
echo '#### First rule - delete all rules ####'
echo '-D'
echo ''
echo '#### 4.1.4 Ensure events that modify date and time information are collected ####'
echo '-a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time-change'
echo '-a always,exit -F arch=b32 -S adjtimex -S settimeofday -S stime -k time-change'
echo '-a always,exit -F arch=b64 -S clock_settime -k time-change'
echo '-a always,exit -F arch=b32 -S clock_settime -k time-change'
echo '-w /etc/localtime -p wa -k time-change'
echo ''
echo '#### 4.1.5 Ensure events that modify user/group information are collected ####'
echo '-w /etc/group -p wa -k identity'
echo '-w /etc/passwd -p wa -k identity'
echo '-w /etc/gshadow -p wa -k identity'
echo '-w /etc/shadow -p wa -k identity'
echo '-w /etc/security/opasswd -p wa -k identity'
echo ''
echo '#### 4.1.6 Ensure events that modify the system'\''s network environment are collected ####'
echo '-a always,exit -F arch=b32 -S sethostname -S setdomainname -k system-locale'
echo '-a always,exit -F arch=b64 -S sethostname -S setdomainname -k system-locale'
echo '-w /etc/issue -p wa -k system-locale'
echo '-w /etc/issue.net -p wa -k system-locale'
echo '-w /etc/hosts -p wa -k system-locale'
echo '-w /etc/network -p wa -k system-locale'
echo '-w /etc/networks -p wa -k system-locale'
echo ''
echo '#### 4.1.7 Ensure events that modify the system'\''s Mandatory Access Controls (MAC'\''s) are collected ####'
echo '-w /etc/selinux/ -p wa -k MAC-policy'
echo '-w /etc/apparmor/ -p wa -k MAC-policy'
echo '-w /etc/apparmor.d/ -p wa -k MAC-policy'
echo ''
echo '#### 4.1.8 Ensure login and logout events are collected ####'
echo '-w /var/log/faillog -p wa -k logins'
echo '-w /var/log/lastlog -p wa -k logins'
echo '-w /var/log/tallylog -p wa -k logins'
echo ''
echo '#### 4.1.9 Ensure session initiation information is collected ###'
echo '-w /var/run/utmp -p wa -k session'
echo '-w /var/run/wtmp -p wa -k session'
echo '-w /var/run/btmp -p wa -k session'
echo ''
echo '#### 4.1.10 Ensure discretionary access control permission modification events are collected ####'
echo '-a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod'
echo '-a always,exit -F arch=b32 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod'
echo '-a always,exit -F arch=b64 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=4294967295 -k perm_mod'
echo '-a always,exit -F arch=b32 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=4294967295 -k perm_mod'
echo '-a always,exit -F arch=b64 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>=1000 -F auid!=4294967295 -k perm_mod'
echo '-a always,exit -F arch=b32 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>=1000 -F auid!=4294967295 -k perm_mod'
echo ''
echo '#### 4.1.11 Ensure unsuccessful unauthorized file access attempts are collected ####'
echo '-a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=4294967295 -k access'
echo '-a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=4294967295 -k access'
echo '-a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=4294967295 -k access'
echo '-a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=4294967295 -k access'
echo ''
echo '#### 4.1.12 Ensure use of privileged commands is collected ####'
echo "$RULES"
echo ''
echo '#### 4.1.13 Ensure successful file system mounts are collected ####'
echo '-a always,exit -F arch=b64 -S mount -F auid>=1000 -F auid!=4294967295 -k mounts'
echo '-a always,exit -F arch=b32 -S mount -F auid>=1000 -F auid!=4294967295 -k mounts'
echo ''
echo '#### 4.1.14 Ensure file deletion events by users are collected ####'
echo '-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete'
echo '-a always,exit -F arch=b32 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete'
echo ''
echo '#### 4.1.15 Ensure changes to system administration scope (sudoers) is collected ####'
echo '-w /etc/sudoers -p wa -k scope'
echo '-w /etc/sudoers.d -p wa -k scope'
echo ''
echo '#### 4.1.16 Ensure system administrator actions (sudolog) are collected ####'
echo '-w /var/log/sudo.log -p wa -k actions'
echo ''
echo '#### 4.1.17 Ensure kernel module loading and unloading is collected ####'
echo '-w /sbin/insmod -p x -k modules'
echo '-w /sbin/rmmod -p x -k modules'
echo '-w /sbin/modprobe -p x -k modules'
echo '-a always,exit -F arch=b64 -S init_module -S delete_module -k modules'
echo ''
echo '#### 4.1.18 Ensure the audit configuration is immutable ####'
echo '-e 2'
} > /etc/audit/rules.d/audit.rules
service auditd restart
stop_spinner $?
} | tee -a $LOG
}
Section 4.2.1 Configure Rsyslog
#################################
#### 4.2.1 Configure rsyslog ####
#################################
function rsyslog_service() {
{
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle || ${OS} = rocky || ${OS} = alma ]]; then
if [ "${OSVER}" = 7 ]; then
os7_rsyslog
elif [[ ${OSVER} = 8 || ${OSVER} = 9 ]]; then
os8_rsyslog
fi
elif [ "${OS}" = ubuntu ]; then
ub_rsyslog
fi
}
}
function os7_rsyslog() {
{
start_spinner 'Configuring Rsyslog Service...'
echo ""
### 4.2.1.1 Ensure rsyslog Service is enabled ###
systemctl enable --now rsyslog
### 4.2.1.2 Ensure logging is configured ###
xargs -n 1 cp -v /etc/rsyslog.conf <<< ""${BACKUP} /etc/rsyslog.conf.bak""
cat > /etc/rsyslog.conf << 'EOF'
##################################################################################################
#### Hardened Rsyslog Configuration File edited to match CIS level 1 requirements ####
#### for questions or changles please contact Phil Connor contact@mylinux.work ####
##################################################################################################
#################
#### MODULES ####
#################
# The imjournal module bellow is now used as a message source instead of imuxsock.
$ModLoad imuxsock # provides support for local system logging (e.g. via logger command)
$ModLoad imjournal # provides access to the systemd journal
#$ModLoad imklog # reads kernel messages (the same are read from journald)
#$ModLoad immark # provides --MARK-- message capability
# Provides UDP syslog reception
#$ModLoad imudp
#$UDPServerRun 514
# Provides TCP syslog reception
#$ModLoad imtcp
#$InputTCPServerRun 514
# Enable non-kernel facility klog messages
# $KLogPermitNonKernelFacility on
###########################
#### GLOBAL DIRECTIVES ####
###########################
# Reset UMASK
$umask 0000
# Set file creation pewrmissions
$FileCreateMode 0640
# Set previously cleared UMASK
$umask 0177
# Where to place auxiliary files
$WorkDirectory /var/lib/rsyslog
# Use default timestamp format
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
# File syncing capability is disabled by default. This feature is usually not required,
# not useful and an extreme performance hit
#$ActionFileEnableSync on
# Include all config files in /etc/rsyslog.d/
$IncludeConfig /etc/rsyslog.d/*.conf
# Turn off message reception via local log socket;
# local messages are retrieved through imjournal now.
$OmitLocalLogging on
# File to store the position in the journal
$IMJournalStateFile imjournal.state
###############
#### RULES ####
###############
# ### Log Anything of Level WARN or Higher. ###
*.warn;mail.none;news.none;authpriv.none;cron.none /var/log/messages
# ### Secure Logging Anything of Level WARN or Higher ###
authpriv.* /var/log/secure
# ### All Mail Logs ###
mail.* -/var/log/mail
# ### Cron Log ###
cron.* /var/log/cron
# ### Everybody Gets Emergency Messages ###
*.emerg :omusrmsg:*
*.=warning;*.=err -/var/log/warn
*.crit /var/log/warn
# ### News Error Logs ###
news.crit -/var/log/news/news.crit
news.err -/var/log/news/news.err
news.notice -/var/log/news/news.notice
# ### Local and Boot Messages ###
local0,local1.* -/var/log/localmessages
local2,local3.* -/var/log/localmessages
local4,local5.* -/var/log/localmessages
local6.* -/var/log/localmessages
local7.* /var/log/boot.log
###############################
#### Begin Forwarding Rule ####
###############################
# ### The Remote SysLog Server host is: name/ip:port, e.g. 192.168.0.1:514, port optional ###
#*.* @@syslog
EOF
echo "
*.* @@${SYSLOG}
####################################
#### End of the Forwarding Rule ####
####################################
" >> /etc/rsyslog.conf
sed -i 's/^[\t]*//' /etc/rsyslog.conf
touch /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
chmod og-rwx /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
chown root:root /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
sed -i 's/*.* @@/#*.* @@/g' /etc/rsyslog.conf
pkill -hup rsyslog
stop_spinner $?
}
}
function os8_rsyslog() {
{
start_spinner 'Configuring Rsyslog Service...'
echo ""
### 4.2.1.1 Ensure rsyslog Service is enabled ###
systemctl enable rsyslog
### 4.2.1.2 Ensure logging is configured ###
xargs -n 1 cp -v /etc/rsyslog.conf <<< ""${BACKUP} /etc/rsyslog.conf.bak""
cat > /etc/rsyslog.conf << 'EOF'
##################################################################################################
#### Hardened Rsyslog Configuration File edited to match CIS level 1 requirements ####
#### for questions or changles please contact Phil Connor contact@mylinux.work ####
##################################################################################################
#################
#### MODULES ####
#################
module(load="imuxsock" # provides support for local system logging (e.g. via logger command)
SysSock.Use="off") # Turn off message reception via local log socket;
# local messages are retrieved through imjournal now.
module(load="imjournal" # provides access to the systemd journal
StateFile="imjournal.state") # File to store the position in the journal
#module(load="imklog") # reads kernel messages (the same are read from journald)
#module(load"immark") # provides --MARK-- message capability
# Provides Rsyslog Forwarding
module(load="omfwd")
# Provides UDP syslog reception
# for parameters see http://www.rsyslog.com/doc/imudp.html
#module(load="imudp") # needs to be done just once
#input(type="imudp" port="514")
# Provides TCP syslog reception
# for parameters see http://www.rsyslog.com/doc/imtcp.html
#module(load="imtcp") # needs to be done just once
#input(type="imtcp" port="514")
###########################
#### GLOBAL DIRECTIVES ####
###########################
# Reset UMASK
$umask 0000
# Set file creation pewrmissions
$FileCreateMode 0640
# Set previously cleared UMASK
$umask 0177
# Where to place auxiliary files
global(workDirectory="/var/lib/rsyslog")
# Use default timestamp format
module(load="builtin:omfile" Template="RSYSLOG_TraditionalFileFormat")
# Include all config files in /etc/rsyslog.d/
include(file="/etc/rsyslog.d/*.conf" mode="optional")
###############
#### RULES ####
###############
# ### Log Anything of Level WARN or Higher. ###
*.warn;mail.none;news.none;authpriv.none;cron.none /var/log/messages
# ### Secure Logging Anything of Level WARN or Higher ###
authpriv.* /var/log/secure
# ### All Mail Logs ###
mail.* -/var/log/mail
# ### Cron Log ###
cron.* /var/log/cron
# ### Everybody Gets Emergency Messages ###
*.emerg :omusrmsg:*
*.=warning;*.=err -/var/log/warn
*.crit /var/log/warn
# ### News Error Logs ###
news.crit -/var/log/news/news.crit
news.err -/var/log/news/news.err
news.notice -/var/log/news/news.notice
# ### Local and Boot Messages ###
local0,local1.* -/var/log/localmessages
local2,local3.* -/var/log/localmessages
local4,local5.* -/var/log/localmessages
local6.* -/var/log/localmessages
local7.* /var/log/boot.log
###############################
#### Begin Forwarding Rule ####
###############################
#action(type="omfwd"
# An on-disk queue is created for this action. If the remote host is
# down, messages are spooled to disk and sent when it is up again.
#queue.filename="fwdRule1" # unique name prefix for spool files
#queue.maxdiskspace="1g" # 1gb space limit (use as much as possible)
#queue.saveonshutdown="on" # save messages to disk on shutdown
#queue.type="LinkedList" # run asynchronously
#action.resumeRetryCount="-1" # infinite retries if host is down
# Remote Logging (we use TCP for reliable delivery)
# remote_host is: name/ip, e.g. 192.168.0.1, port optional e.g. 10514
# Target="remote_host" Port="XXX" Protocol="tcp")
EOF
echo "
Target=\"${SYSLOG}" Port="514" Protocol="tcp\"
####################################
#### End of the Forwarding Rule ####
####################################
" >> /etc/rsyslog.conf
sed -i 's/^[\t]*//' /etc/rsyslog.conf
touch /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
chmod og-rwx /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
chown root:root /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
sed -i 's/Target="" Port="514" Protocol="tcp"/#Target="" Port="514" Protocol="tcp"/g' /etc/rsyslog.conf
pkill -hup rsyslog
stop_spinner $?
}
}
function ub_rsyslog() {
{
start_spinner 'Configuring Rsyslog Service...'
echo ""
service rsyslog stop
mknod -m 640 /dev/xconsole c 1 3
chown syslog:adm /dev/xconsole
### 4.2.1.1 Ensure rsyslog Service is enabled ###
systemctl enable rsyslog
### 4.2.1.2 Ensure logging is configured ###
xargs -n 1 cp -v /etc/rsyslog.conf <<< ""${BACKUP} /etc/rsyslog.conf.bak""
no_show << "EOF" > /etc/rsyslog.conf
##################################################################################################
#### Hardened Rsyslog Configuration File edited to match CIS level 1 requirements ####
#### for questions or changles please contact Phil Connor contact@mylinux.work ####
##################################################################################################
#################
#### MODULES ####
#################
module(load="imuxsock") # provides support for local system logging
#module(load="immark") # provides --MARK-- message capability
# provides UDP syslog reception
#module(load="imudp")
#input(type="imudp" port="514")
# provides TCP syslog reception
#module(load="imtcp")
#input(type="imtcp" port="514")
# provides kernel logging support and enable non-kernel klog messages
module(load="imklog" permitnonkernelfacility="on")
###########################
#### GLOBAL DIRECTIVES ####
###########################
# Use default timestamp format
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
# Use traditional timestamp format.
# To enable high precision timestamps, comment out the following line.
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
# Filter duplicated messages
$RepeatedMsgReduction on
# Reset UMASK
$Umask 0000
# Set the default permissions for all log files.
$FileOwner syslog
$FileGroup adm
$FileCreateMode 0640
$DirCreateMode 0755
$Umask 0177
$PrivDropToUser syslog
$PrivDropToGroup syslog
# Where to place spool and state files
$WorkDirectory /var/spool/rsyslog
# Include all config files in /etc/rsyslog.d/
$IncludeConfig /etc/rsyslog.d/*.conf
###############################
#### Begin Forwarding Rule ####
###############################
$PreserveFQDN on
$ActionQueueFileName queue
$ActionQueueMaxDiskSpace 1g
$ActionQueueSaveOnShutdown on
$ActionQueueType LinkedList
$ActionResumeRetryCount -1
# ### The Remote SysLog Server host is: name/ip:port, e.g. 192.168.0.1:514, port optional ###
#*.* @@syslog
EOF
echo "
*.* @@${SYSLOG}:514
####################################
#### End of the Forwarding Rule ####
####################################
" >> /etc/rsyslog.conf
sed -i 's/^[\t]*//' /etc/rsyslog.conf
xargs -n 1 cp -v /etc/rsyslog.d/50-default.conf <<< ""${BACKUP} /etc/rsyslog.d/50-default.conf.bak""
no_show << "EOF" > /etc/rsyslog.d/50-default.conf
##################################################################################################
#### Hardened Rsyslog Configuration File edited to match CIS level 1 requirements ####
#### for questions or changles please contact Phil Connor contact@mylinux.work ####
##################################################################################################
###############
#### RULES ####
###############
# Default rules for rsyslog.
#
# For more information see rsyslog.conf(5) and /etc/rsyslog.conf
#
# First some standard log files. Log by facility.
#
auth,authpriv.* /var/log/auth.log
*.*;auth,authpriv.none -/var/log/syslog
#cron.* /var/log/cron.log
#daemon.* -/var/log/daemon.log
kern.* -/var/log/kern.log
#lpr.* -/var/log/lpr.log
mail.* -/var/log/mail.log
#user.* -/var/log/user.log
#
# Logging for the mail system. Split it up so that
# it is easy to write scripts to parse these files.
#
#mail.info -/var/log/mail.info
#mail.warn -/var/log/mail.warn
mail.err /var/log/mail.err
#
# Logging for INN news system.
#
news.crit /var/log/news/news.crit
news.err /var/log/news/news.err
news.notice -/var/log/news/news.notice
#
# Some "catch-all" log files.
#
#*.=debug;\
# auth,authpriv.none;\
# news.none;mail.none -/var/log/debug
#*.=info;*.=notice;*.=warn;\
# auth,authpriv.none;\
# cron,daemon.none;\
# mail,news.none -/var/log/messages
#
# Emergencies are sent to everybody logged in.
#
*.emerg :omusrmsg:*
#
# I like to have messages displayed on the console, but only on a virtual
# console I usually leave idle.
#
#daemon,mail.*;\
# news.=crit;news.=err;news.=notice;\
# *.=debug;*.=info;\
# *.=notice;*.=warn /dev/tty8
# The named pipe /dev/xconsole is for the `xconsole' utility. To use it,
# you must invoke `xconsole' with the `-file' option:
#
# $ xconsole -file /dev/xconsole [...]
#
# NOTE: adjust the list below, or you'll go crazy if you have a reasonably
# busy site..
#
daemon.*;mail.*;\
news.err;\
*.=debug;*.=info;\
*.=notice;*.=warn |/dev/xconsole
EOF
touch /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
chmod og-rwx /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
chown root:root /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
sed -i 's/*.* @@[[:blank:]]*:514/#*.* @@/g' /etc/rsyslog.conf
systemctl start rsyslog
pkill -hup rsyslog
stop_spinner $?
} | tee -a $LOG
}
Section 4.2.1.2 Ensure Journald Service is enabled
####################################################
#### 4.2.1.2 Ensure Journald Service is enabled ####
####################################################
function journald_config() {
{
start_spinner 'Configuring Journald Log Retension...'
echo ""
### 4.2.2.1 Ensure journald is configured to send logs to rsyslog ###
sed -i 's/#ForwardToSyslog=yes/ForwardToSyslog=yes/g' /etc/systemd/journald.conf
### 4.2.2.2 Ensure journald is configured to compress large log files ###
sed -i 's/#Compress=yes/Compress=yes/g' /etc/systemd/journald.conf
### 4.2.2.3 Ensure journald is configured to write logfiles to persistent disk ###
sed -i 's/#Storage=auto/Storage=persistent/g' /etc/systemd/journald.conf
stop_spinner $?
} | tee -a $LOG
}
Section 4.2.2 Ensure Journald is Configured
##################################
#### 4.2.2 Configure journald ####
##################################
function logfile_permissions() {
{
start_spinner 'Configuring Permissions on all Logfiles...'
echo ""
### 4.2.4 Ensure permissions on all logfiles are configured ###
find /var/log -type f -exec chmod g-wx,o-rwx {} +
### 4.3 Ensure logrotate is configured ###
cp /etc/logrotate.conf $BACKUP
sed -i 's/ create 0664 root utmp/ create 0640 root utmp/g' /etc/logrotate.conf
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle ]]; then
if [ "${OSVER}" = 8 ]; then
sed -i 's/ create 0664 root utmp/ create 0640 root utmp/g' /etc/logrotate.d/btmp
sed -i 's/ create 0664 root utmp/ create 0640 root utmp/g' /etc/logrotate.d/wtmp
fi
fi
stop_spinner $?
} | tee -a $LOG
}
Section 5.1.1 Ensure Cron Daemon is Enabled
#############################################
#### 5.1.1 Ensure cron daemon is enabled ####
#############################################
function crond_enabled() {
{
start_spinner 'Configuring Permissions on Cron Daemon...'
echo ""
### 5.1.1.1 Ensure cron daemon is enabled ###
if [ "${OS}" = ubuntu ]; then
if ! systemctl is-enabled cron; then
systemctl enable cron
fi
else
if ! systemctl is-enabled crond; then
systemctl enable crond
fi
fi
### Ensure permissions on /etc/crontab are configured ###
chown root.root /etc/crontab
chmod og-rwx /etc/crontab
### 5.1.3 Ensure permissions on /etc/cron.hourly are configured ###
chown root.root /etc/cron.hourly
chmod og-rwx /etc/cron.hourly
### 5.1.4 Ensure permissions on /etc/cron.daily are configured ###
chown root.root /etc/cron.daily
chmod og-rwx /etc/cron.daily
### 5.1.5 Ensure permissions on /etc/cron.weekly are configured ###
chown root.root /etc/cron.weekly
chmod og-rwx /etc/cron.weekly
### 5.1.6 Ensure permissions on ?etc/cron.monthly are configured ###
chown root.root /etc/cron.monthly
chmod og-rwx /etc/cron.monthly
### 5.1.7 Ensure permissions on /etc/cron.d are configured ###
chown root.root /etc/cron.d
chmod og-rwx /etc/cron.d
### 5.1.8 Ensure at/cron is restricted to authorized users ###
stat /etc/cron.deny
if [ $? != 1 ]; then
rm -rf /etc/cron.deny
fi
stat /etc/at.deny
if [ $? != 1 ]; then
rm -rf /etc/at.deny
fi
if ! stat /etc/cron.allow; then
touch /etc/cron.allow
chown root.root /etc/cron.allow
chmod og-rwx /etc/cron.allow
fi
if ! stat /etc/at.allow; then
touch /etc/at.allow
chown root.root /etc/at.allow
chmod og-rwx /etc/cron.allow
fi
stop_spinner $?
} | tee -a $LOG
}
Section 5.2 Ensure SSH Server is Configured
######################################
#### 5.2 SSH Server Configuration ####
######################################
function config_sshd() {
{
start_spinner 'Configuring SSh Server...'
echo ""
### 5.2.1 Ensure permissions on /etc/ssh/sshd_config are configured ###
xargs -n 1 cp -v ${SSHD_FILE} <<< ""${BACKUP} ${SSHD_FILE}.bak""
chown root.root ${SSHD_FILE}
chmod og-rwx ${SSHD_FILE}
### 5.2.2. Ensure SSH Protocol is set to 2 ###
if ! grep -qi "Protocol 2" ${SSHD_FILE}; then
echo 'Protocol 2' >> ${SSHD_FILE}
else
sed -i 's/#Protocol 2/Protocol 2/g' ${SSHD_FILE}
fi
### 5.2.3 Ensure SSH LogLevel is set to info ###
if ! grep -qi "LogLevel INFO" ${SSHD_FILE}; then
echo "LogLevel INFO" ${SSHD_FILE}
else
sed -i 's/#LogLevel INFO/LogLevel INFO/g' ${SSHD_FILE}
fi
### 5.2.4 Ensure SSH X11 forwarding is disabled ###
if ! grep -qi "X11Forwarding yes" ${SSHD_FILE}; then
echo "X11Forwarding no" ${SSHD_FILE}
else
sed -i 's/X11Forwarding yes/X11Forwarding no/g' ${SSHD_FILE}
fi
### 5.2.5 Ensure SSH MaxAuthTries is set to 4 or less ###
if ! grep -qi "MaxAuthTries 6" ${SSHD_FILE}; then
echo "MaxAuthTries 4" >> ${SSHD_FILE}
else
sed -i 's/#MaxAuthTries 6/MaxAuthTries 4/g' ${SSHD_FILE}
fi
### 5.2.6 Ensure SSH IgnoreRhosts is enabled ###
if ! grep -qi "IgnoreRhosts yes" ${SSHD_FILE}; then
echo "IgnoreRhosts yes" >> ${SSHD_FILE}
else
sed -i 's/#IgnoreRhosts yes/IgnoreRhosts yes/g' ${SSHD_FILE}
fi
### 5.2.7 Ensure SSH HostbasedAuthentication is disabled ###
if ! grep -qi "HostbasedAuthentication no" ${SSHD_FILE}; then
echo "HostbasedAuthentication no" >> ${SSHD_FILE}
else
sed -i 's/#HostbasedAuthentication no/HostbasedAuthentication no/g' ${SSHD_FILE}
fi
### 5.2.8 Ensure SSH root login is disabled ###
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle ]]; then
if ! grep -qi "#PermitRootLogin" ${SSHD_FILE}; then
sed -i 's/PermitRootLogin yes/PermitRootLogin no/g' ${SSHD_FILE}
else
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/g' ${SSHD_FILE}
fi
elif [ "${OS}" = ubuntu ]; then
if ! grep -qi "prohibit-password" ${SSHD_FILE}; then
sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin no/g' ${SSHD_FILE}
fi
fi
### Ensure SSH PermitEmptyPasswords is disabled ###
sed -i 's/#PermitEmptyPasswords no/PermitEmptyPasswords no/g' ${SSHD_FILE}
### 5.2.10 Ensure SSH PermitUserEnvironment is disables ###
if ! grep -qi "#PermitUserEnvironment" ${SSHD_FILE}; then
echo "PermitUserEnvironment no" >> ${SSHD_FILE}
else
sed -i 's/#PermitUserEnvironment no/PermitUserEnvironment no/g' ${SSHD_FILE}
fi
### 5.2.11 Ensure ony approved MAC algorithms are used ###
if ! grep -qi "MACs" ${SSHD_FILE}; then
echo "MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256" >> ${SSHD_FILE}
else
sed -i 's/MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com/MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256/g' ${SSHD_FILE}
fi
if ! grep -qi "#ClientAliveInterval" ${SSHD_FILE}; then
echo "ClientAliveInterval 300" >> ${SSHD_FILE}
else
sed -i 's/#ClientAliveInterval 0/ClientAliveInterval 300/g' ${SSHD_FILE}
fi
if ! grep -qi "#ClientAliveCountMax" ${SSHD_FILE}; then
echo "ClientAliveCountMax ${MAXCOUNT}" >> ${SSHD_FILE}
else
sed -i "s/#ClientAliveCountMax 3/ClientAliveCountMax \"${MAXCOUNT}\"/g" ${SSHD_FILE}
fi
### 5.2.13 Ensure SSH LoginGraceTime is set to one minute or less ###
if ! grep -qi "LoginGraceTime 120" ${SSHD_FILE}; then
sed -i 's/#LoginGraceTime 2m/LoginGraceTime 60/g' ${SSHD_FILE}
else
sed -i 's/LoginGraceTime 120/LoginGraceTime 60/g' ${SSHD_FILE}
fi
### 5.2.14 Ensure SSH access is limited ###
echo 'AllowUsers *@*' >> ${SSHD_FILE}
### 5.2.15 Ensure SSH warning banner is configured ###
if ! grep -qi "#Banner none" ${SSHD_FILE}; then
sed -i 's/#Banner \/etc\/issue.net/Banner \/etc\/issue.net/g' ${SSHD_FILE}
else
sed -i 's/#Banner none/Banner \/etc\/issue.net/g' ${SSHD_FILE}
fi
### 5.2.16 Ensure only strong Key Exchange algorithms are used ###
if ! grep -qi "kexalgorithms" ${SSHD_FILE}; then
echo "KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256" >> ${SSHD_FILE}
fi
### 5.2.21 Ensure SSH MaxStartups is configured ###
if ! grep -qi "maxstartups" ${SSHD_FILE}; then
echo "MaxStartups 10:30:60" >> ${SSHD_FILE}
else
sed -i 's/#MaxStartups 10:30:100/MaxStartups 10:30:60/g' ${SSHD_FILE}
fi
### Configuring additional SSH settings ###
if ! grep -qi "#MaxSessions" ${SSHD_FILE}; then
echo "MaxSessions 2" >> ${SSHD_FILE}
else
sed -i 's/#MaxSessions 10/MaxSessions 2/g' ${SSHD_FILE}
fi
if ! grep -qi "#AllowAgentForwarding" ${SSHD_FILE}; then
echo "AllowAgentForwarding no" >> ${SSHD_FILE}
else
sed -i 's/#AllowAgentForwarding yes/AllowAgentForwarding no/g' ${SSHD_FILE}
fi
if ! grep -qi "#AllowTcpForwarding" ${SSHD_FILE}; then
echo "AllowTcpForwarding no" >> ${SSHD_FILE}
else
sed -i 's/#AllowTcpForwarding yes/AllowTcpForwarding no/g' ${SSHD_FILE}
fi
sed -i 's/#PrintMotd yes/PrintMotd no/g' ${SSHD_FILE}
if ! grep -qi "PrintLastLog" ${SSHD_FILE}; then
echo "PrintLastLog no" >> ${SSHD_FILE}
else
sed -i 's/#PrintLastLog yes/PrintLastLog no/g' ${SSHD_FILE}
fi
if ! grep -qi "TCPKeepAlive" ${SSHD_FILE}; then
sed -i 's/TCPKeepAlive yes/TCPKeepAlive no/g' ${SSHD_FILE}
else
sed -i 's/#TCPKeepAlive yes/TCPKeepAlive no/g' ${SSHD_FILE}
fi
if ! grep -qi "Compression" ${SSHD_FILE}; then
echo "Compression no" >> ${SSHD_FILE}
else
sed -i 's/#Compression delayed/Compression no/g' ${SSHD_FILE}
fi
if ! grep -qi "UseDNS" ${SSHD_FILE}; then
echo "UseDNS no" >> ${SSHD_FILE}
else
sed -i 's/#UseDNS yes/UseDNS no/g' ${SSHD_FILE}
sed -i 's/#UseDNS no/UseDNS no/g' ${SSHD_FILE}
fi
if ! grep -qi "#PasswordAuthentication" ${SSHD_FILE}; then
sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/g' ${SSHD_FILE}
else
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' ${SSHD_FILE}
fi
echo 'Ciphers aes128-ctr,aes192-ctr,aes256-ctr' >> ${SSHD_FILE}
systemctl restart sshd
stop_spinner $?
} | tee -a $LOG
}
Section 5.3 Configure PAM
###########################
#### 5.3 Configure PAM ####
###########################
function config_pam() {
{
start_spinner 'Configuring PAM Server...'
echo ""
### 5.3.1 Ensure password creation requirements are configured ###
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle ]]; then
xargs -n 1 cp -v /etc/security/pwquality.conf <<< ""${BACKUP} /etc/security/pwquality.conf.bak""
sed -i 's/minlen = 8/minlen = 14/g' /etc/security/pwquality.conf
### 5.3.2 Ensure lockout for failed password attempts is configured ###
xargs -n 1 cp -v /etc/pam.d/password-auth <<< ""${BACKUP} /etc/pam.d/password-auth.bak""
no_show << EOF > /etc/pam.d/password-auth
########################################################################################
#### This password-auth file edited to match CIS level 1 requirements for questions ####
#### or changes please contact Phil Connor contact@mylinux.work ####
#### Please don't edit it unless you know what your doing ####
########################################################################################
#%PAM-1.0
# User changes will be destroyed the next time authconfig is run.
auth required pam_env.so
auth required pam_faildelay.so delay=2000000
auth required pam_faillock.so preauth audit silent deny=5 unlock_time=900
auth [success=1 default=bad] pam_unix.so
auth sufficient pam_fprintd.so
auth sufficient pam_unix.so nullok try_first_pass
auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=900
auth sufficient pam_faillock.so authsucc audit deny=5 unlock_time=900
auth requisite pam_succeed_if.so uid >= 1000 quiet_success
auth required pam_deny.so
account required pam_unix.so
account sufficient pam_localuser.so
account sufficient pam_succeed_if.so uid < 1000 quiet
account required pam_permit.so
account required pam_faillock.so
password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= enforce_for_root
password required pam_pwhistory.so remember=5 use_authlok
password sufficient pam_unix.so remember=5 sha512 shadow try_first_pass use_authtok
password required pam_deny.so
session optional pam_keyinit.so revoke
session required pam_limits.so
-session optional pam_systemd.so
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session required pam_unix.so
##########################################
#### Logging key strokes of all USERS ####
##########################################
session required pam_tty_audit.so disable=* enable=* log_passwd
EOF
xargs -n 1 cp -v /etc/pam.d/system-auth <<< ""${BACKUP} /etc/pam.d/system-auth.bak""
no_show << EOF > /etc/pam.d/system-auth
######################################################################################
#### This system-auth file edited to match CIS level 1 requirements for questions ####
#### or changes please contact Phil Connor contact@mylinux.work ####
#### Please don't edit it unless you know what your doing ####
######################################################################################
#%PAM-1.0
# User changes will be destroyed the next time authconfig is run.
auth required pam_env.so
auth required pam_faildelay.so delay=2000000
auth required pam_faillock.so preauth audit silent deny=5 unlock_time=900
auth [success=1 default=bad] pam_unix.so
auth sufficient pam_fprintd.so
auth sufficient pam_unix.so nullok try_first_pass
auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=900
auth sufficient pam_faillock.so authsucc audit deny=5 unlock_time=900
auth requisite pam_succeed_if.so uid >= 1000 quiet_success
auth required pam_deny.so
account required pam_unix.so
account sufficient pam_localuser.so
account sufficient pam_succeed_if.so uid < 1000 quiet
account required pam_permit.so
account required pam_faillock.so
password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= enforce_for_root
password required pam_pwhistory.so remember=5 use_authlok
password sufficient pam_unix.so remember=5 sha512 shadow try_first_pass use_authtok
password required pam_deny.so
session optional pam_keyinit.so revoke
session required pam_limits.so
-session optional pam_systemd.so
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session required pam_unix.so
##########################################
#### Logging key strokes of all USERS ####
##########################################
session required pam_tty_audit.so disable=* enable=* log_passwd
EOF
fi
if [ "${OS}" = ubuntu ]; then
debconf-set-selections <<< ""postfix postfix/mailname string "${HOSTNAME}"""
debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'"
${PAKMGR} remove libpam-cracklib
${PAKMGR} install libpam-pwquality --assume-yes
xargs -n 1 cp -v /etc/pam.d/common-password<<< ""${BACKUP} /etc/pam.d/common-password.bak""
#sed -i 's/password[[:blank:]]*requisite[[:blank:]]*pam_pwquality.so retry=3/password requisite pam_pwquality.so retry=3 difok=3 reject_username enforce_for_root/g' /etc/pam.d/common-password
sed -i 's/# minlen = 8/minlen = 14/g' /etc/security/pwquality.conf
sed -i 's/# dcredit = 0/dcredit=-1/g' /etc/security/pwquality.conf
sed -i 's/# ucredit = 0/ucredit=-1/g' /etc/security/pwquality.conf
sed -i 's/# ocredit = 0/ocredit=-1/g' /etc/security/pwquality.conf
sed -i 's/# lcredit = 0/lcredit=-1/g' /etc/security/pwquality.conf
no_show << EOF >> /etc/pam.d/common-password
################################################
#### 5.3.3 Ensure password reuse is limited ####
################################################
password required pam_unix.so remember=5
EOF
no_show << EOF >> /etc/pam.d/common-auth
#########################################################################
#### 5.3.2 Ensure lockout for failed password attempts is configured ####
#########################################################################
auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900
##########################################
#### Logging key strokes of all USERS ####
##########################################
session required pam_tty_audit.so disable=* enable=* log_passwd
EOF
fi
stop_spinner $?
} | tee -a $LOG
}
Section 5.4 User Accounts and Enviroments
############################################
#### 5.4 User Accounts and Environments ####
############################################
function accounts() {
{
start_spinner 'Configuring User Accts and Environments...'
echo ""
LODEFS="/etc/login.defs"
#### 5.4.1.1 Ensure password expiration is 90 days or less ####
#### 5.4.1.2 Ensure minimum days between password changes is 7 days or more ####
#### 5.4.1.3 Ensure password expiration warning days is 7 or more ####
if [ -e ${LODEFS} ]; then
cp ${LODEFS} ${LODEFS}.tmp
awk '($1 ~ /^PASS_MAX_DAYS/) { $2="90" }
($1 ~ /^PASS_MIN_DAYS/) { $2="7" }
($1 ~ /^PASS_WARN_AGE/) { $2="10" }
($1 ~ /^PASS_MIN_LEN/) { $2="14" }
{ print }' ${LODEFS}.tmp > ${LODEFS}
rm ${LODEFS}.tmp
fi
cut -d: -f1 /etc/passwd | while read -r NAME
do
uid=$(id -u "${NAME}")
if [ "${uid}" -ge 1000 ] && [ "${uid}" != 65534 ]; then
chage -M 90 -m 7 -W 10 -I 30 "${NAME}"
fi
done
if [ "${OS}" = ubuntu ]; then
no_show << EOF >> ${LODEFS}
##################################################################
#### Make it More Difficult to Bruteforce the Hashed Password ####
##################################################################
SHA_CRYPT_MIN_ROUNDS 5000
SHA_CRYPT_MAX_ROUNDS 10000
EOF
sed -i 's/pam_faildelay.so delay=3000000/pam_faildelay.so delay=300000000/g' /etc/pam.d/login
else
no_show << EOF >> ${LODEFS}
############################################################################
#### Establish a forced five-second minimum delay between failed logins ####
############################################################################
FAIL_DELAY 5
##################################################################
#### Make it More Difficult to Bruteforce the Hashed Password ####
##################################################################
SHA_CRYPT_MIN_ROUNDS 5000
SHA_CRYPT_MAX_ROUNDS 10000
EOF
fi
chown root:root ${LODEFS}
chmod 0640 ${LODEFS}
#### 5.4.1.4 Ensure inactive password lock is 30 days or less ####
useradd -D -f 30
stop_spinner $?
} | tee -a $LOG
}
function config_users_permissions() {
{
start_spinner 'Configuring User Permissions...'
echo ""
#### 5.4.2 Ensure system accounts are non-login ####
awk -F: '($3 < 1000) {print $1 }' /etc/passwd | while read -r user
do
if [ "$user" != "root" ]; then
usermod -L "$user"
if [ "$user" != "sync" ] && [ "$user" != "shutdown" ] && [ "$user" != "halt" ]; then
usermod -s /usr/sbin/nologin "$user"
fi
fi
done
#### 5.4.3 Ensure default group for the root account is GID 0 ####
usermod -g 0 root
groupadd dev
groupadd dba
touch /etc/sudoers.d/cis_conf
chmod 440 /etc/sudoers.d/cis_conf
if [ "${OS}" = ubuntu ]; then
sed -i 's/sudo:x:27:/sudo:x:27:root,ubuntu/g' /etc/group
sed -i 's/sudo:*::/sudo:*::root,ubuntu/g' /etc/gshadow
sed -i 's/%sudo[[:blank:]]*ALL=(ALL:ALL)[[:blank:]]*ALL/%sudo ALL=\(ALL:ALL\) NOPASSWD:ALL/g' /etc/sudoers
else
grep -qi "wheel" /etc/group
if [ $? != 1 ]; then
sed -i 's/%wheel[[:blank:]]*ALL=(ALL)[[:blank:]]*ALL/# %wheel ALL=\(ALL\) ALL/g' /etc/sudoers
sed -i 's/^#\s*\(%wheel\s*ALL=(ALL)\s*NOPASSWD:\s*ALL\)/\1/' /etc/sudoers
sed -i 's/wheel:x:10:opc/wheel:x:10:root,opc/g' /etc/group
sed -i 's/wheel:::opc/wheel:::root,opc/g' /etc/gshadow
fi
fi
{
echo "####################"
echo "#### Networking ####"
echo "####################"
} >> /etc/sudoers.d/local_conf
if [ "${OS}" = ubuntu ]; then
{
echo "Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /sbin/iptables, /sbin/mii-tool"
echo ""
} >> /etc/sudoers.d/local_conf
else
{
echo "Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /usr/bin/net, /sbin/iptables, /usr/bin/rfcomm, /usr/bin/wvdial, /sbin/iwconfig, /sbin/mii-tool"
echo ""
} >> /etc/sudoers.d/local_conf
fi
{
echo "#################################################"
echo "#### Installation and management of software ####"
echo "#################################################"
} >> /etc/sudoers.d/cis_conf
if [ "${OS}" = ubuntu ]; then
{
echo "Cmnd_Alias SOFTWARE = usr/bin/apt, /usr/bin/dpkg, /usr/bin/apt-get"
echo ""
} >> /etc/sudoers.d/local_conf
else
{
echo "Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/up2date, /usr/bin/yum"
echo ""
} >> /etc/sudoers.d/local_conf
fi
{
echo "##################"
echo "#### Services ####"
echo "##################"
echo "Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig, /usr/bin/systemctl start, /usr/bin/systemctl stop, /usr/bin/systemctl reload, /usr/bin/systemctl restart, /usr/bin/systemctl status, /usr/bin/systemctl enable, /usr/bin/systemctl disable"
echo ""
echo "######################################"
echo "#### Updating the locate database ####"
echo "######################################"
echo "Cmnd_Alias LOCATE = /usr/bin/updatedb"
echo ""
echo "#################"
echo "#### Storage ####"
echo "#################"
echo "Cmnd_Alias STORAGE = /sbin/fdisk, /sbin/sfdisk, /sbin/parted, /sbin/partprobe, /bin/mount, /bin/umount"
echo ""
echo "################################"
echo "#### Delegating permissions ####"
echo "################################"
echo "Cmnd_Alias DELEGATING = /usr/sbin/visudo, /bin/chown, /bin/chmod, /bin/chgrp"
echo ""
echo "###################"
echo "#### Processes ####"
echo "###################"
echo "Cmnd_Alias PROCESSES = /bin/nice, /bin/kill, /usr/bin/kill, /usr/bin/killall"
echo ""
echo "#################"
echo "#### Drivers ####"
echo "#################"
echo "Cmnd_Alias DRIVERS = /sbin/modprobe"
echo ""
echo "###########################################################################"
echo "#### Reboot and ShutDown removed from DBA's and Developers 3/4/20 - PC ####"
echo "###########################################################################"
echo "Cmnd_Alias SHUTDOWN = /sbin/shutdown, /sbin/reboot, /sbin/halt, /sbin/poweroff"
echo ""
echo "###########################"
echo "#### Our System Groups ####"
echo "###########################"
echo "%dba ALL= NOPASSWD: /usr/bin/su - applmgr, /usr/bin/su - oracle, !NETWORKING, !SOFTWARE, !SERVICES, !STORAGE, !DELEGATING, !PROCESSES, !LOCATE, !DRIVERS, !SHUTDOWN"
echo "%dev ALL= NOPASSWD: /usr/bin/su - applmgr, !NETWORKING, !SOFTWARE, !SERVICES, !STORAGE, !DELEGATING, !PROCESSES, !LOCATE, !DRIVERS, !SHUTDOWN"
} >> /etc/sudoers.d/local_conf
#### 5.4.4 Ensure default user umask is 027 or more restrictive ####
if [ "${OS}" = "ubuntu" ]; then
grep -Eq "^(\s*)umask\s+\S+(\s*#.*)?\s*$" /etc/bash.bashrc && sed -ri "s/^(\s*)umask\s+\S+(\s*#.*)?\s*$/\1umask 027\2/" /etc/bash.bashrc || echo "umask 027" >> /etc/bash.bashrc
else
grep -Eq "^(\s*)umask\s+\S+(\s*#.*)?\s*$" /etc/bashrc && sed -ri "s/^(\s*)umask\s+\S+(\s*#.*)?\s*$/\1umask 027\2/" /etc/bashrc || echo "umask 027" >> /etc/bashrc
fi
grep -Eq "^(\s*)umask\s+\S+(\s*#.*)?\s*$" /etc/profile && sed -ri "s/^(\s*)umask\s+\S+(\s*#.*)?\s*$/\1umask 027\2/" /etc/profile || echo "umask 027" >> /etc/profile
#### 5.4.5 Ensure default user shell timeout is 900 seconds or less ####
if grep TMOUT=900 /etc/bashrc; then
sed -i 's/TMOUT=900/#TMOUT=900/g' /etc/bashrc
fi
if grep TMOUT=900 /etc/profile; then
sed -i 's/TMOUT=900/#TMOUT=900/g' /etc/profile
fi
cat >> /etc/profile << 'EOF'
if [ "$(id -nu)" == "root" ] || [ "$(id -nu)" == "opc" ]; then
TMOUT=3600
readonly TMOUT
export TMOUT
else
TMOUT=900
readonly TMOUT
export TMOUT
fi
EOF
cat >> /etc/bashrc << 'EOF'
if [ "$(id -nu)" == "root" ] || [ "$(id -nu)" == "opc" ]; then
if ! echo $TMOUT | grep -q 3600; then
TMOUT=3600
readonly TMOUT
export TMOUT
fi
else
if ! echo $TMOUT | grep -q 900; then
TMOUT=900
readonly TMOUT
export TMOUT
fi
fi
EOF
#### 5.4.5A Ensure default user umask is configured - system wide ####
sed -ri 's/^([^#]+\s+)?(umask\s+)(\S+\s*)(\s+.*)?$/\1\2 027\4/' /etc/login.defs
sed -ri 's/^([^#]+\s+)?(umask\s+)(\S+\s*)(\s+.*)?$/\1\2 027\4/' /etc/profile
sed -ri 's/^([^#]+\s+)?(umask\s+)(\S+\s*)(\s+.*)?$/\1\2 027\4/' /etc/bashrc
touch /etc/profile.d/cis_profile.sh
chmod 644 /etc/profile.d/cis_profile.sh
echo "
################################
### Added for CIS Compliance ###
################################
umask 077
" > /etc/profile.d/cis_profile.sh
#### 5.5 Ensure root login is restricted to system console ####
xargs -n 1 cp -v /etc/securetty <<< ""${BACKUP} /etc/securetty.bak""
echo "console" > /etc/securetty
### 5.6 Ensure access to the su command is restricted ###
PAMSU="/etc/pam.d/su"
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle ]]; then
xargs -n 1 cp -v ${PAMSU} <<< ""${BACKUP} ${PAMSU}.bak""
if [ -e ${PAMSU} ]; then
cp ${PAMSU} ${PAMSU}.tmp
awk '( $1=="#auth" && $2=="required" && $3~"pam_wheel.so" ) { print "auth\t\trequired\t",$3,"\tuse_uid"; next };
{ print }' ${PAMSU}.tmp > ${PAMSU}
chown root:root ${PAMSU}
chmod 0644 ${PAMSU}
rm ${PAMSU}.tmp
fi
elif [ "${OS}" = ubuntu ]; then
sed -i 's/# auth[[:blank:]]*required[[:blank:]]*pam_wheel.so/auth required pam_wheel.so use_uid/g' /etc/pam.d/su
sed -i 's/auth required pam_wheel.so use_uid deny group=nosu/#auth required pam_wheel.so deny group=nosu/g' /etc/pam.d/su
fi
stop_spinner $?
} | tee -a $LOG
}
Section 6.1 System Permissions
################################
#### 6.1 System Permissions ####
################################
function audit_file_permissions() {
{
start_spinner 'Auditing File Permissions...'
echo ""
### 6.1.1 Audit system file permissions ###
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle ]]; then
rpm -Va --nomtime --nosize --nomd5 --nolinkto
elif [ "${OS}" = ubuntu ]; then
${PAKMGR} install debsums
debsums -s
fi
### 6.1.2 Ensure permissions on /etc/passwd are configured ###
chmod 644 /etc/passwd
chown root.root /etc/passwd
### 6.1.3 Ensure permissions on /etc/shadow are configured ###
chmod 000 /etc/shadow
chown root.root /etc/shadow
### 6.1.4 Ensure permissions on /etc/group are configured ###
chmod 644 /etc/group
chown root.root /etc/group
### 6.1.5 Ensure permissions on /etc/gshadow are configured ###
chmod 000 /etc/gshadow
chown root:root /etc/gshadow
### 6.1.6 Ensure permissions on /etc/passwd- are configured ###
chmod 644 /etc/passwd-
chown root.root /etc/passwd-
### 6.1.7 Ensure permissions on /etc/shadow- are configured ###
chmod 000 /etc/shadow-
chown root.root /etc/shadow-
### 6.1.4 Ensure permissions on /etc/group- are configured ###
chmod 644 /etc/group-
chown root.root /etc/group-
### 6.1.5 Ensure permissions on /etc/gshadow- are configured ###
chmod 000 /etc/gshadow-
chown root:root /etc/gshadow-
stop_spinner $?
} | tee -a $LOG
}
Section 6.1.1 World Writable Files
####################################
#### 6.1.1 World Writable Files ####
####################################
function world_writable_files() {
{
start_spinner 'Resetting Permissions on all World Writable, Unowned and Ungrouped Files...'
echo ""
#### 6.1.10 Ensure no world writable files exist ####
df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type f -perm -0002
#### 6.1.11 Ensure no unowned files or directories exist ####
df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -nouser -ls
#### 6.1.12 Ensure no ungrouped files or directories exist ####
df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -nogroup -ls
#### 6.1.12 Audit SUID executables ####
df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type f -perm -4000 -print
#### 6.1.14 Audit SGID executables ####
df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type f -perm -2000 -print
stop_spinner $?
} | tee -a $LOG
}
Section 6.2 User and Group Settings
#####################################
#### 6.2 User and Group Settings ####
#####################################
function user_group_settings() {
{
start_spinner 'Configuring User and Group Settings...'
echo ""
### 6.2.1 Ensure password fields are not empty ###
awk -F: '($2 == "" ) { print $1 " does not have a password "}' /etc/shadow
### 6.2.2 Ensure no legacy "+" entries exist in /etc/passwd ###
grep '^+:' /etc/passwd
### 6.2.3 Ensure no legacy "+" entries exist in /etc/shadow ###
grep '^+:' /etc/shadow
### 6.2.4 Ensure no legacy "+" entries exist in /etc/group ###
grep '^+:' /etc/group
### 6.2.5 Ensure root is the only UID 0 account ###
awk -F: '($3 == 0) { print $1 }' /etc/passwd
### 6.2.6 Ensure root PATH Intergrity ###
if [ "$(echo "$PATH" | grep ::)" != "" ]; then
echo "Empty Directory in PATH (::)"
fi
if [ "$(echo "$PATH" | grep :$)" != "" ]; then
echo "Trailing : in PATH"
fi
p=$(echo "$PATH" | sed -e 's/::/:/' -e 's/:$//' -e 's/:/ /g')
set -- "$p"
while [ "$1" != "" ];
do
if [ "$1" = "." ]; then
echo "PATH contains ."
shift
continue
fi
if [ -d "$1" ]; then
# shellcheck disable=SC2012
dirperm=$(ls -ldH "$1" | cut -f1 -d" ")
if [ "$(echo "${dirperm}" | cut -c6)" != "-" ]; then
echo "Group Write permission set on directory $1"
fi
if [ "$(echo "${dirperm}" | cut -c9)" != "-" ]; then
echo "Other Write permission set on directory $1"
fi
# shellcheck disable=SC2012
dirown=$(ls -ldH "$1" | awk '{print $3}')
if [ "${dirown}" != "root" ] ; then
echo "$1 is not owned by root"
fi
else
echo "$1 is not a directory"
fi
shift
done
stop_spinner $?
} | tee -a $LOG
}
Section 6.2 Continued - Part 1
###############################################
#### 6.2 User and Group Settings Continued ####
###############################################
function home_directories() {
{
start_spinner 'Checking and Configuring User Directories...'
echo ""
#### 6.2.7 Ensure all users' home directories exist ####
awk -F: '{ print $1 " " $3 " " $6 }' /etc/passwd | while read -r user uid dir
do
if [ "${uid}" -ge 500 ] && [ -d "${dir}" ] && [ "${user}" != "nfsnobody" ]; then
owner=$(stat -L -c "%U" "${dir}")
if [ "${owner}" != "${user}" ]; then
echo "The home directory (${dir}) of user ${user} is owned by ${owner}."
fi
fi
done
#### 6.2.8 Ensure users' home directories permissions are 750 or more restrictive ####
grep -Ev '(root|halt|sync|shutdown)' /etc/passwd | awk -F: '($8 == "PS" && $7 != "/sbin/nologin") { print $6 }' | while read -r dir
do
# shellcheck disable=SC2012
dirperm=$(ls -ld "${dir}" | cut -f1 -d" ")
if [ "$( echo "${dirperm}" | cut -c6 )" != "-" ]; then
echo "Group Write permission set on directory $dir"
fi
if [ "$( echo "${dirperm}" | cut -c8 )" != "-" ]; then
echo "Other Read permission set on directory $dir"
fi
if [ "$( echo "${dirperm}" | cut -c9 )" != "-" ]; then
echo "Other Write permission set on directory $dir"
fi
if [ "$( echo "${dirperm}" | cut -c10 )" != "-" ]; then
echo "Other Execute permission set on directory $dir"
fi
done
#### 6.2.9 Ensure users own their home directories ####
awk -F: '{ print $1 " " $3 " " $6 }' /etc/passwd | while read -r user uid dir
do
if [ "$uid" -ge 500 ] && [ ! -d "$dir" ] && [ "$user" != "nfsnobody" ]; then
echo "The home directory ($dir) of user $user does not exist."
fi
done
stop_spinner $?
} | tee -a $LOG
}
Section 6.2 Continued - Part 2
########################################################
#### 6.2 User and Group Settings Continued - Part 2 ####
########################################################
function dot_files() {
{
start_spinner 'Checking and Configuring Hidden Files and Directories...'
echo ""
#### 6.2.10 Ensure users' dot files are not group or world writable ####
grep -Ev '(root|sync|halt|shutdown)' /etc/passwd | awk -F: '($7 != "/sbin/nologin") { print $6 }' | while read -r dir
do
for file in "$dir"/.[A-Za-z0-9]*
do
if [ ! -h "${file}" ] && [ -f "${file}" ]; then
# shellcheck disable=SC2012
fileperm=$(ls -ld "$file" | cut -f1 -d" ")
if [ "$(echo "$fileperm" | cut -c6 )" != "-" ]; then
echo "Group Write permission set on file $file"
fi
if [ "$(echo "$fileperm" | cut -c9 )" != "-" ]; then
echo "Other Write permission set on file $file"
fi
fi
done
done
awk -F: '($3 >= 500) { print $6 }' /etc/passwd | while read -r DIR
do
for FILE in "$DIR"/.[A-Za-z0-9]*
do
if [ ! -h "$FILE" ] && [ -f "$FILE" ]; then
chmod go-w "$FILE"
fi
done
done
#### 6.2.11 Ensure no users have .forward files ####
awk -F: '{ print $6 }' /etc/passwd | while read -r dir
do
if [ ! -h "$dir/.forward" ] && [ -f "$dir/.forward" ]; then
echo ".forward file $dir/.forward exists"
fi
done
#### 6.2.12 Ensure no users have .netrc files ####
awk -F: '{ print $6 }' /etc/passwd | while read -r dir
do
if [ ! -h "$dir/.netrc" ] && [ -f "$dir/.netrc" ]; then
echo ".netrc file $dir/.netrc exists"
fi
done
#### Ensure users' .netrc Files are not group or world accessible ####
grep -Ev '(root|halt|sync|shutdown)' /etc/passwd | awk -F: '($7 != "/sbin/nologin") { print $6 }' | while read -r dir
do
for file in $dir/.netrc
do
if [ ! -h "$file" ] && [ -f "$file" ]; then
# shellcheck disable=SC2012
fileperm=$(ls -ld "$file" | cut -f1 -d" ")
if [ "$(echo "$fileperm" | cut -c5 )" != "-" ]; then
echo "Group Read set on $file"
fi
if [ "$(echo "$fileperm" | cut -c6 )" != "-" ]; then
echo "Group Write set on $file"
fi
if [ "$(echo "$fileperm" | cut -c7 )" != "-" ]; then
echo "Group Execute set on $file"
fi
if [ "$(echo "$fileperm" | cut -c8 )" != "-" ]; then
echo "Other Read set on $file"
fi
if [ "$(echo "$fileperm" | cut -c9 )" != "-" ]; then
echo "Other Write set on $file"
fi
if [ "$(echo "$fileperm" | cut -c10 )" != "-" ]; then
echo "Other Execute set on $file"
fi
fi
done
done
#### Ensure no users have .rhosts files ####
grep -Ev '(root|halt|sync|shutdown)' /etc/passwd | awk -F: '($7 != "/sbin/nologin") { print $6 }' | while read -r dir
do
for file in $dir/.rhosts; do
if [ ! -h "$file" ] && [ -f "$file" ]; then
echo ".rhosts file in $dir"
fi
done
done
stop_spinner $?
} | tee -a $LOG
}
Section 6.2 Continued - Part 3
########################################################
#### 6.2 User and Group Settings Continued - Part 3 ####
########################################################
function group_gid_uid() {
{
start_spinner 'Checking that all Group and UserIDs are valid...'
echo ""
#### Ensure all groups in etc/passwd exist in /etc/group ####
cut -s -d: -f4 /etc/passwd | sort -u | while read -r i
do
if ! grep -q -P "^.*?:x:$i:" /etc/group; then
echo "Group $i is referenced by /etc/passwd but does not exist in /etc/group"
fi
done
#### Ensure no duplicate UIDs exist ####
cut -f3 -d":" /etc/passwd | sort -n | uniq -c | while read -r x
do
[ -z "${x}" ] && break
# shellcheck disable=SC2086
set - ${x}
if [ "$1" -gt 1 ]; then
users=$(awk -F: '($3 == n) { print $1 }' n="$2" /etc/passwd | xargs)
echo "Duplicate UID ($2): ${users}"
fi
done
#### 6.2.17 Ensure no duplicate GIDs exist ####
cut -f3 -d":" /etc/group | sort -n | uniq -c | while read -r x
do
[ -z "${x}" ] && break
# shellcheck disable=SC2086
set - ${x}
if [ "$1" -gt 1 ]; then
grps=$(gawk -F: '($3 == n) { print $1 }' n="$2" /etc/group | xargs)
echo "Duplicate GID ($2): ${grps}" >> ${LOG} 2>&1
fi
done
#### 6.2.18 Ensure no duplicate user names exist ####
cut -f1 -d":" /etc/passwd | sort -n | /usr/bin/uniq -c | while read -r x
do
[ -z "${x}" ] && break
# shellcheck disable=SC2086
set - ${x}
if [ "$1" -gt 1 ]; then
uids=$(gawk -F: '($1 == n) { print $3 }' n="$2" /etc/passwd | xargs)
echo "Duplicate User Name ($2): ${uids}"
fi
done
#### 6.2.19 Ensure no duplicate group names exist ####
cut -f1 -d":" /etc/group | sort -n | uniq -c | while read -r x
do
[ -z "${x}" ] && break
set - "${x}"
if [ "$1" -gt 1 ]; then
gids=$(gawk -F: '($1 == n) { print $3 }' n="$2" /etc/group | xargs)
echo "Duplicate Group Name ($2): ${gids}"
fi
done
stop_spinner $?
} | tee -a $LOG
}
This is the end of the security code blocks.
now for the additional addons,
Add-on 1 - Unattended Upgrade
#########################################
#### Auto Unattended Security Upates ####
#########################################
function auto_updates() {
{
start_spinner 'Configuring Auto Security Updates...'
echo ""
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle || ${OS} = rocky || ${OS} = alma ]]; then
if [ "${OSVER}" = 7 ]; then
${PAKMGR} install yum-cron
sed -i 's/update_cmd = default/update_cmd = security/g' /etc/yum/yum-cron.conf
sed -i 's/apply_updates = no/apply_updates = yes/g' /etc/yum/yum-cron.conf
sed -i 's/download_updates = no/download_updates = yes/g' /etc/yum/yum-cron-hourly.conf
systemctl enable yum-cron
systemctl start yum-cron
fi
if [ "${OSVER}" = 8 ]; then
${PAKMGR} install dnf-automatic
sed -i 's/upgrade_type = default/upgrade_type = security/g' /etc/dnf/automatic.conf
sed -i 's/apply_updates = no/apply_updates = yes/g' /etc/dnf/automatic.conf
systemctl enable --now dnf-automatic.timer
fi
elif [ "${OS}" = ubuntu ]; then
${PAKMGR} install unattended-upgrades apticron
touch /etc/apt/apt.conf.d/20auto-upgrades
no_show << EOF > /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";
EOF
sed -i 's/\/\/Unattended-Upgrade\:\:Mail "root";/Unattended-Upgrade\:\:Mail "root";/g' /etc/apt/apt.conf.d/50unattended-upgrades
fi
stop_spinner $?
} | tee -a $LOG
}
this part of the script only set auto update for the security packages, when your working with a large server farm this makes it a little easier to keep up with them, not required just something I use, (also with a slight change you can do full upgrades if you wanted)
Add-on 2 - Audit Log compression
################################
#### Auditd Compression Log ####
################################
function compress_auditd() {
{
start_spinner 'Installing Auditd Cmpression Cron Script...'
echo ""
touch /etc/cron.daily/audit
{
echo '#!/bin/bash'
echo ""
echo "##############################################################################################"
echo "#### This auditd script is to get a daily compressed log rotation using a daily cron job. ####"
echo "#### in /etc/cron.daily for questions or changles please contact Phil Connor ####"
echo "#### Phil Connor contact@mylinux.work Remember to set ####"
echo "#### max_log_file_action = ignore in /etc/audit/auditd.conf when using this script ####"
echo "##############################################################################################"
echo ""
echo "FORMAT=\"%F_%T\" # Customize timestamp format as desired Default is (%F_%T which gives you audit.log.2015-02-26_15:43:46)"
echo "COMPRESS=gzip # Change to bzip2 or xz as desired (Default is gzip)"
echo "KEEP=60 # Number of days of compressed log files to keep (Default is 60)"
echo "ROTATE_TIME=5 # Amount of time in seconds to wait for auditd to rotate its logs. (Default is 5)"
echo ""
echo "rename_and_compress_logs() {"
echo " for file in \$(find /var/log/audit/ -regextype posix-extended -regex '.*audit.log.[0-9]{1,}\$')"
echo " do"
echo " timestamp=\$(ls -l --time-style=\"+ \${FORMAT}\" \${file} | awk '{print \$6}')"
echo " newfile=\${file%.[0-9]}.\${timestamp}"
echo " mv -v \"\${file} \"\${newfile}\""
echo " \"\${COMPRESS}\" -v \"\${newfile}\""
echo " done"
echo "}"
echo ""
echo "delete_old_compressed_logs() {"
echo " find /var/log/audit/ -mtime +\"\${KEEP}\" -regextype posix-extended -regex \".*audit\\.log\\..*(xz|gz|bz2)\$\" -delete"
echo "}"
echo ""
echo "service auditd rotate"
echo -e "sleep \$ROTATE_TIME"
echo "rename_and_compress_logs"
echo "delete_old_compressed_logs"
} > /etc/cron.daily/audit
chmod 755 /etc/cron.daily/audit
stop_spinner $?
} | tee -a $LOG
}
No matter what you picked in the Audit Log Menu, this little script will compress and date the file for you to conserve drive space.
Addon 3 - SysStat
#######################################################
#### Install SysStat Redhat/CentOS 7 and 8, Ubuntu ####
#######################################################
function install_sysstat() {
{
start_spinner 'Installing and Configuring SysStat...'
echo ""
${PAKMGR} install sysstat
if [ "${OS}" = ubuntu ]; then
sed -i 's/ENABLED="false"/ENABLED="true"/g' /etc/default/sysstat
no_show << EOF > /etc/cron.d/sysstat
# The first element of the path is a directory where the debian-sa1
# script is located
PATH=/usr/lib/sysstat:/usr/sbin:/usr/sbin:/usr/bin:/sbin:/bin
# Activity reports every 10 minutes everyday
5-55/10 * * * * root command -v debian-sa1 > /dev/null && debian-sa1 1 1
# Additional run at 23:59 to rotate the statistics file
59 23 * * * root command -v debian-sa1 > /dev/null && debian-sa1 60 2
EOF
else
if [ ! -d /var/log/sa ]; then
mkdir /var/log/sa
fi
fi
systemctl enable sysstat
systemctl start sysstat
stop_spinner $?
} | tee -a $LOG
}
Add-on 4 - Rootkit Hunter
##############################################################
#### Install RootKit Hunter Redhat/CentOS 7 and 8, Ubuntu ####
##############################################################
function install_rkhunter() {
{
start_spinner 'Installing and Configuring RKHunter...'
echo ""
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = rocky || ${OS} = alma ]]; then
${PAKMGR} install epel-release
${PAKMGR} install rkhunter
elif [ "${OS}" = oracle ]; then
if [ "${OSVER}" = 7 ]; then
${PAKMGR} install oracle-epel-release-el7
sed -i 's/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-epel-ol7.repo
fi
if [ "${OSVER}" = 8 ]; then
${PAKMGR} install oracle-epel-release-el8
sed -i 's/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-epel-ol8.repo
fi
${PAKMGR} install rkhunter
elif [ "${OS}" = ubuntu ]; then
debconf-set-selections <<< ""postfix postfix/mailname string "${HOSTNAME}"""
debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'"
DEBIAN_FRONTEND=noninteractive ${PAKMGR} install rkhunter >> ${LOG} 2>&1
fi
rkhunter --update
rkhunter --propupd
sed -i 's/ALLOW_SSH_ROOT_USER=unset/ALLOW_SSH_ROOT_USER=no/g' /etc/rkhunter.conf
stop_spinner $?
} | tee -a $LOG
}
Add-on 5 - LMD (Linux Malware Detect)
###################################################
#### Install LMD Redhat/CentOS 7 and 8, Ubuntu ####
###################################################
function install_lmd() {
{
start_spinner 'Installing and Configuring MalDetect...'
echo ""
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = rocky || ${OS} = alma ]]; then
${PAKMGR} install epel-release
${PAKMGR} install mailx inotify-tools tar wget
elif [ "${OS}" = oracle ]; then
if [ "${OSVER}" = 7 ]; then
${PAKMGR} install oracle-epel-release-el7
sed -i 's/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-epel-ol7.repo
fi
if [ "${OSVER}" = 8 ]; then
${PAKMGR} install oracle-epel-release-el8
sed -i 's/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-epel-ol8.repo
fi
${PAKMGR} install mailx inotify-tools tar wget
elif [ "${OS}" = ubuntu ]; then
export DEBIAN_FRONTEND=noninteractive
${PAKMGR} install inotify-tools wget
fi
wget http://www.rfxn.com/downloads/maldetect-current.tar.gz
tar -xvzf maldetect-current.tar.gz
cd maldetect-1* || return $?
./install.sh
cd .. || return $?
rm -rf maldetect-*
if [ "${OS}" = ubuntu ]; then
ln -s /usr/local/maldetect/maldet /bin/maldet
hash -r
fi
sed -i 's/email_alert="0"/email_alert="1"/g' /usr/local/maldetect/conf.maldet
sed -i 's/email_addr="you@domain.com"/email_addr="root@localhost"/g' /usr/local/maldetect/conf.maldet
sed -i 's/quarantine_hits="0"/quarantine_hits="1"/g' /usr/local/maldetect/conf.maldet
sed -i 's/quarantine_clean="0"/quarantine_clean="1"/g' /usr/local/maldetect/conf.maldet
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = oracle ]]; then
${PAKMGR} install clamav clamav-devel
elif [ "${OS}" = ubuntu ]; then
export DEBIAN_FRONTEND=noninteractive
${PAKMGR} install clamav clamav-daemon clamdscan clamav-freshclam
fi
freshclam
stop_spinner $?
} | tee -a $LOG
}
Add-on 6 - Logwatch
##########################
#### Install Logwatch ####
##########################
function install_logwatch() {
{
start_spinner 'Installing and Configuring LogWatch...'
${PAKMGR} install logwatch
LOG_ZZ=/usr/share/logwatch/default.conf/services/zz-disk_space.conf
# shellcheck disable=SC2016
sed -i 's/#$show_home_dir_sizes = 1/$show_home_dir_sizes = 1/g' $LOG_ZZ
# shellcheck disable=SC2016
sed -i 's/#$home_dir = "\/home"/$home_dir = "\/home"/g' $LOG_ZZ
# shellcheck disable=SC2016
sed -i 's/#$show_mail_dir_sizes = 1/#$show_mail_dir_sizes = 1/g' $LOG_ZZ
# shellcheck disable=SC2016
sed -i 's/#$mail_dir = "\/var\/spool\/mail/$mail_dir = "\/var\/spool\/mail/g' $LOG_ZZ
# shellcheck disable=SC2016
sed -i 's/#$show_disk_usage = 1/$show_disk_usage = 1/g' $LOG_ZZ
# shellcheck disable=SC2016
sed -i 's/$HTTP_IGNORE_ERROR_HACKS = 0/$HTTP_IGNORE_ERROR_HACKS = 1/g' /usr/share/logwatch/default.conf/services/http.conf
sed -i 's/Detail = Low/Detail = Med/g' /usr/share/logwatch/default.conf/logwatch.conf
stop_spinner $?
} | tee -a $LOG
}
Include 1 - Oracle EBS Pre Install
###############################
#### Oracle EBS PreInstall ####
###############################
function oci_oracle_ebs_setup() {
{
start_spinner 'Configuring Server for Oracle EBS/WebLogic...'
if [ "${SRVTYPE}" != 3 ]; then
if [[ ${OS} = centos || ${OS} = redhat || ${OS} = rocky || ${OS} = alma ]]; then
${PAKMGR} install oracle-ebs-server-R12-preinstall openmotif21
oci-network-config -X ens3
sed -i 's/PRESERVE_HOSTINFO=0/PRESERVE_HOSTINFO=2/g' /etc/oci-hostname.conf
groupadd dba
groupadd dev
touch /etc/oraInst.loc
chmod 600 /etc/oraInst.loc
chown applmgr. /etc/oraInst.loc
elif [ "${OS}" = ubuntu ]; then
echo ""
echo -e "\e[7m**** !EBS PreInstall for Ubuntu is not supported! ****\e[0m"
echo ""
fi
fi
if [ "${SRVTYPE}" == 3 ]; then
oci-network-config -X ens3
sed -i 's/PRESERVE_HOSTINFO=0/PRESERVE_HOSTINFO=2/g' /etc/oci-hostname.conf
fi
} | tee -a $LOG
}
All Combined Function Calls
########################
#### Function Calls ####
########################
function oci_rh_ub_common() {
{
check_root
backup
make_swap
time_set
disable_filesystems
tmp_directory
stickybit
gpgkeys
aide_install
sudo_changes
boot_load
core_dumps
sysctl_conf
pre_link
se_troubleshoot_mcs
unconf_daemons
se_linux
banners
inet_service
ntp_config
chrony_cfg
update_security
unsecure_services
mail_config
addon_inet_services
service_clients
tcp_wrappers
auto_updates
uncommon_protocols
iptables_config
audit_accounting
rsyslog_service
journald_config
logfile_permissions
crond_enabled
compress_auditd
config_sshd
config_pam
accounts
config_users_permissions
audit_file_permissions
world_writable_files
user_group_settings
home_directories
dot_files
group_gid_uid
install_sysstat
install_rkhunter
install_lmd
install_logwatch
}
}
OCI and AWS Firewall Change Calls
##################
#### OCI Only ####
##################
function oci_only() {
{
oci_iptables
}
}
##################
#### AWS Only ####
##################
function aws_only() {
{
aws_iptables
}
}
Install Complete
This shows that the install has completed, it is strongly recommend that you open another ssh window to the server while this window is there to make sure you can still connect, otherwise you will have to console into the system to fix it.
You can download this script here
Comments