#!/bin/bash
#
# Copyright 2010 Emeric Nasi
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-
#    This file is part of Glyptodon
#
#    Glyptodon is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    Glyptodon is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with Glyptodon  If not, see <http://www.gnu.org/licenses/>.
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-
#
###################################################################################################
######  - glyptodon.sh  -                                                                     #####
#####   Description : Finds and logs threats in a Linux/UNIX* filesystem                      #####
#####        Author : Emeric Nasi                                                             #####
#####       Version : 1.2-b                                                                   #####
#####       Contact ; glyptodon[at]sevagas.com                                                #####
#####  Requirements : Run by root (uid=0)                                                     #####
#####                 *UNIX use of glyptodon might require prerequisit and have restrictions  #####
#####                  More infos on http://www.sevagas.com/?-Glyptodon-                      #####
###################################################################################################


declare -r VERSION_MAJ=1
declare -r VERSION_MIN=2
declare -r VERSION_STATE="b"
declare -r AUTHOR="Emeric Nasi"
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[ -d /usr/gnu/bin/ ] && PATH=/usr/gnu/bin/:$PATH # If possible we use GNU tools
export PATH

#User must be root
if [ `/usr/bin/id -u` != 0 ]
then
	echo -e "\033[40m\033[1;31m Error: Sorry, this script needs root access. -> abort $0 script\033[0m" >&2
	exit 1
fi

# script  vars
MINIMUM_TOOLS="cat cut find grep stat touch wc"
OPTIONNAL_TOOLS="column date lsof sed sort"
CAPABILITIES_TOOLS="getcap sed xargs"

# display help function
display_help ()
{
        echo
        echo "Usage: $0 [-c | --capabilities-scan] [-f | --full-scan] [-h | --help] [-p BINARIES_PATH | --path=BINARIES_PATH] [-l LOG_FILE | --log=LOG_FILE] [-s SKIPED_DIRS | --skip-dir=SKIPED_DIRS [-V | --Version] "
	echo "Glyptodon finds and logs potential threats in a Linux file-system"
	echo "This script verifies the filesystem for potential risks, such as suid files, world writeable files, etc and log them."
	echo "It also writes out some stats (like the number of suid files for example) "
	echo "Options : "
	echo "  -c, --capabilities-scan  Scan system for risks linked to files with POSIX file capabilities."
	echo "			This scan is not run by default, even with --full-scan option."
	echo "			NOTE : This scan type might not be possible on your system."
	echo "  -f, --full-scan	Display and log more features than the normal scan."
	echo "			Full scan is slow and can write out a lot of stuff so it is not recommended for automatic scans."
	echo "  -h, --help		Display this help."
	echo "  -p, --path		This option allows you to choose a path for the binaries used by the script."
	echo "			For example, if you have a cdrom with static compiled binaries."
	echo "			(the results will be more trustfull if the system is corrupted)"
	echo "			Required binaries : $MINIMUM_TOOLS (Glyptodon wont run without them)."
	echo "			Optionnal binaries : $OPTIONNAL_TOOLS (If you want 100% Glyptodon features)."
	echo "			Capabilities scan binaries : $CAPABILITIES_TOOLS (required for option --capabilities-scan)."
	echo "  -l, --log		This option allows you to log the output of Glyptodon in a given file"
	echo "			I generally use --log=/var/log/glyptodon.log"
	echo "  -s, --skip-dir	System scans can be long."
	echo "			This option accelerates this process by avoiding to search into some directories."
	echo "			Directories must be separated by commas. "
	echo "			It can be usefull to use --skip-dir=\"/mnt/windows\" if you have mounted a windows partition inside."
	echo "			If you don't use the option glyptodon will search the entire Windows partition and will be very, very slow"
	echo "			For a regular scan I personnaly use --skip-dir=\"/mnt,/media\""
	echo "			NOTE : This option does not apply to the --capabilities-scan scan"
	echo "  -V, --Version		Display glyptodon version."
	echo
        exit 3
}
show_version ()
{
	echo "$VERSION_MAJ.$VERSION_MIN-$VERSION_STATE"
	exit 0
}

# parameters interpretation
while getopts "cfhp:-:l:-:s:-:V" OPT
do
    # long options processing
    [ $OPT = "-" ] && case "${OPTARG%%=*}" in
	capabilities-scan) OPT="c" ;;
        full-scan) OPT="f" ;;
        help) OPT="h" ;;
        path) OPT="p" ; OPTARG="${OPTARG#*=}" ;;
	log) OPT="l" ; OPTARG="${OPTARG#*=}" ;;
        skip-dir) OPT="s" ; OPTARG="${OPTARG#*=}" ;;
        Version) OPT="V" ;;
        *) display_help  ;;
    esac
   # options processing
    case $OPT in
	c) CAPABILITIES=1 ;;
        f) FULL_SCAN=1 ;;
        h) display_help ;;
        l)
		LOG_FILE="$OPTARG"
	;;
	p)
		if [  -d $OPTARG ]
		then
			BIN_PATH="$OPTARG"
		else
			echo "$OPTARG is not a directory"  >&2
			exit 1
		fi
	;;
        s)
		SKIPED_DIRS="$OPTARG,"
	;;
        V) show_version ;;
        *) display_help ;;
    esac
done


echo
echo  " - Glyptodon - "

[ $LOG_FILE ] &&
{
	if ! (umask 027 && touch "$LOG_FILE" && test -f "$LOG_FILE" ) # we create the logfile if it doesn't exist (we also test it is a regular file)
	then
		echo "Error : Couln't create $LOG_FILE -> exit">&2
		exit 1
	fi
	if [ -L "$LOG_FILE" ]
	then
		echo "Fatal : $LOG_FILE is a symbolic link, this can be a security issue -> exit" >&2
		exit 1
	fi
}
writeAndLog () {
	echo "$1"
	[ $LOG_FILE ] && echo "$1" >> "$LOG_FILE"
}
writeAndLog
[ $LOG_FILE ] &&
{
	echo "Glyptodon $VERSION_MAJ.$VERSION_MIN-$VERSION_STATE running" >> "$LOG_FILE"
	command -v date &>/dev/null &&  echo "$(date '+%Y-%m-%d_%H-%M') " >> "$LOG_FILE"
}

# I use the next functions to allow to set the path of the binaries used by the script
# -> for the -p option
# Setting path for binaries (-p option)
if [ $BIN_PATH ]
then
	# Set new PATH
	PATH="$BIN_PATH"
	export PATH
	# Verify presence of compulsory tools
	for  tool in $MINIMUM_TOOLS
	do
		if ! command -v "$tool" &>/dev/null
		then
			writeAndLog "Error : Couldn't find '$tool' -> Abort script."
			exit 1
		fi
	done
	for  tool in $OPTIONNAL_TOOLS
	do
		if ! command -v "$tool" &>/dev/null
		then
			writeAndLog "Warning : Couldn't find '$tool' -> Glyptodon is not running with 100% features."
		fi
	done
	[ $CAPABILITIES ] &&
	{
		for  tool in $CAPABILITIES_TOOLS
		do
			if ! command -v "$tool" &>/dev/null
			then
				writeAndLog "Error : Couldn't find '$tool' (required for --capabilities option) -> Abort script."
				exit 1
			fi
		done
	}
fi
# Verifye system is compatiable and has the tools to manage POSIX capabilities
if [ $CAPABILITIES ]
then
	if   ! grep -x "CONFIG_SECURITY_FILE_CAPABILITIES=y" /boot/config-`cat /proc/version | cut -d " " -f 3` &> /dev/null
	then
		writeAndLog "Error : Your kernel configuration does not allow file capabilities -> Abort script."
		exit 1
	fi
	for  tool in $CAPABILITIES_TOOLS
	do
		if ! command -v "$tool" &>/dev/null
		then
			writeAndLog "Error : Couldn't find '$tool' (required for --capabilities option) -> Abort script."
			exit 1
		fi
	done
fi
# Replace sort by dummy function
if ! command -v sort &>/dev/null
then
	function sort()
	{
		while read data
		do
			echo $data
		done
	}
fi
# Replace column by dummy function
if ! command -v column &>/dev/null
then
	function column()
	{
		while read data
		do
			echo $data
		done
	}
fi
# Replace sed by dummy function
if ! command -v sed &>/dev/null
then
	function sed()
	{
		while read data
		do
			echo $data
		done
	}
fi
# processing skipped directories
find_options=""
if [ $SKIPED_DIRS ]
then
	find_options+=" ( "
	cpt=1
	tmp=`echo "$SKIPED_DIRS" | cut -d "," -f $cpt`
	until [ -z $tmp ]
	do
		[ $cpt -gt 1 ] && find_options+=" -o " # I build find options to avoid to enter the given dirs
		find_options+="-wholename $tmp "
		let cpt++
		tmp=`echo "$SKIPED_DIRS" | cut -d "," -f $cpt`
	done
	find_options+=" ) "
	find_options+="-prune -false -o " # -false to avoid to print the name of the directory
	unset tmp
	unset cpt
fi

#################################### General stats... ##################################
writeAndLog "*** System informations ***"
# Counting suid files
NB_SUID=`find /  $find_options -perm -4000 2>/dev/null  | wc -l`
NB_SUID_ROOT=`find /  $find_options  -perm -4000 -user root 2>/dev/null | wc -l`
# Counting sgid files
NB_SGID=`find /  $find_options  -perm -2000 2>/dev/null | wc -l`
NB_SGID_ROOT=`find / $find_options  -perm -2000 -user root 2>/dev/null | wc -l`
writeAndLog "$NB_SUID setuid files ($NB_SUID_ROOT belongs to root)"
writeAndLog "$NB_SGID setgid files ($NB_SGID_ROOT belongs to root)"

# Counting world writeable files in /bin
NB_WWBin=`find   /bin $find_options ! -type l -perm -002  2>/dev/null | wc -l`
# Counting world writeable files in /sbin
NB_WWSbin=`find  /sbin $find_options ! -type l  -perm -002  2>/dev/null | wc -l`
# Counting world writeable files in /usr
NB_WWUsr=`find   /usr $find_options ! -type l   -perm -002  2>/dev/null | wc -l`
# Counting world writeable files in /opt
NB_WWOpt=`find   /opt $find_options ! -type l   -perm -002  2>/dev/null | wc -l`
# Counting world writeable files in /etc
NB_WWEtc=`find  /etc $find_options ! -type l  -perm -002  2>/dev/null | wc -l`
# Counting world writeable files in /lib
NB_WWLib=`find   /lib $find_options ! -type l -perm -002  2>/dev/null | wc -l`
# Counting world writeable files in /home
NB_WWHome=`find  /home $find_options ! -type l  -perm -002  2>/dev/null | wc -l`
# Counting world writeable files in /var
NB_WWVar=`find  /var $find_options ! -type l  -perm -002  2>/dev/null | wc -l`
# Counting world writeable directories in /boot
NB_WWBoot=`find  /boot $find_options ! -type l  -perm -002  2>/dev/null | wc -l`
# Counting world writeable files in /dev
NB_WWDev=`find  /dev $find_options ! -type l  -perm -002  2>/dev/null | wc -l`
# Counting world writeable files in /tmp
NB_WWTmp=`find  /tmp $find_options ! -type l  -perm -002  2>/dev/null | wc -l`
# Counting world writeable files in /root
NB_WWRoot=`find  /root $find_options ! -type l  -perm -002  2>/dev/null | wc -l`
# Counting world writeable files in /sys
NB_WWSys=`find  /sys $find_options ! -type l  -perm -002  2>/dev/null | wc -l`
writeAndLog "World writeable files (all types, exept sym links) :"
writeAndLog " $NB_WWBin in /bin, $NB_WWSbin in /sbin,  $NB_WWUsr in /usr,  $NB_WWOpt in /opt, $NB_WWEtc in /etc, $NB_WWLib in /lib, $NB_WWHome in /home  "
writeAndLog " $NB_WWVar in /var, $NB_WWBoot in /boot, $NB_WWDev in /dev, $NB_WWTmp in /tmp, $NB_WWRoot in /root, $NB_WWSys in /sys"
if [ $FULL_SCAN ]
then
	#  Counting sticky files
	NB_STICK=`find /  $find_options -perm -1000 2>/dev/null  | wc -l`
	NB_STICK_ROOT=`find /  $find_options  -perm -1000 -user root 2>/dev/null | wc -l`
	writeAndLog "$NB_STICK sticky bit files ($NB_STICK_ROOT belongs to root)"
	# Counting broken sim links files in /bin
	NB_BLBin=`find -L  /bin $find_options -type l -maxdepth 8  2>/dev/null | wc -l`
	# Counting broken sim links files in /sbin
	NB_BLSbin=`find -L  /sbin $find_options -type l -maxdepth 8  2>/dev/null | wc -l`
	# Counting broken sim links files in /usr
	NB_BLUsr=`find -L   /usr $find_options -type l -maxdepth 8  2>/dev/null | wc -l`
	# Counting broken sim links files in /opt
	NB_BLOpt=`find -L   /opt $find_options -type l -maxdepth 8  2>/dev/null | wc -l`
	# Counting broken sim links files in /etc
	NB_BLEtc=`find -L  /etc $find_options -type l -maxdepth 8 2>/dev/null | wc -l`
	# Counting broken sim links files in /lib
	NB_BLLib=`find -L   /lib $find_options  -type l -maxdepth 8  2>/dev/null | wc -l`
	# Counting broken sim links files in /home
	NB_BLHome=`find -L  /home $find_options -type l -maxdepth 8 2>/dev/null | wc -l`
	# Counting broken sim links files in /var
	NB_BLVar=`find -L  /var $find_options -type l -maxdepth 8 2>/dev/null | wc -l`
	# Counting broken sim links directories in /boot
	NB_BLBoot=`find -L  /boot $find_options -type l -maxdepth 8 2>/dev/null | wc -l`
	# Counting broken sim links files in /dev
	NB_BLDev=`find -L  /dev $find_options -type l -maxdepth 8 2>/dev/null | wc -l`
	# Counting broken sim links files in /tmp
	NB_BLTmp=`find -L  /tmp $find_options -type l -maxdepth 8 2>/dev/null | wc -l`
	# Counting broken sim links files in /root
	NB_BLRoot=`find -L  /root $find_options -type l -maxdepth 8 2>/dev/null | wc -l`
	# Counting broken sim links files in /sys
	NB_BLSys=`find -L  /sys $find_options -type l -maxdepth 8 2>/dev/null | wc -l`
	writeAndLog "Broken symbolic links :"
	writeAndLog " $NB_BLBin in /bin, $NB_BLSbin in /sbin,  $NB_BLUsr in /usr, $NB_BLOpt in /opt, $NB_BLEtc in /etc, $NB_BLLib in /lib, $NB_BLHome in /home  "
	writeAndLog " $NB_BLVar in /var, $NB_BLBoot in /boot, $NB_BLDev in /dev, $NB_BLTmp in /tmp, $NB_BLRoot in /root, $NB_BLSys in /sys"
	# Hard link scan
	NB_HL=`find / $find_options ! -type d -links +1 2>/dev/null | wc -l`
	writeAndLog "Hard links : "
	writeAndLog "$NB_HL non directory files have more than one hard link."
	# Ownership stats
	writeAndLog "Ownership stats..."
	for user in `cat /etc/passwd |  cut -d: -f1` # get usernames
	do
		NB_OwnedFiles=`find / $find_options -user  $user 2>/dev/null | wc -l`
		writeAndLog "User $user owns $NB_OwnedFiles files"
	done
fi

if command -v lsof &>/dev/null
then
	servers=`lsof | grep -E "IPv4|IPv6|COMMAND.*USER" |  sed -r  "s/ +/ /g" | cut -d " " -f 1,2,3,5,8,9 | column -t | sed "s/.*/ &/"`
	writeAndLog "TCP IP opened sockets :"
	writeAndLog "$servers"
	unset servers
fi

# All the IFS stuff is to allow to correctly check filenames containing whitespace
OLDIFS=$IFS
IFS=$'\012'

####################################### Detailed risk scanning #####################################
writeAndLog "*** Detailled scan ***"

if [ $FULL_SCAN ]
then
	IFS=$OLDIFS
	for line in `cat /etc/passwd | grep "/bin/bash"  | cut -d: -f1,6` # get usernames and homes for user using /bin/bash
	do
		IFS=$OLDIFS
		user_home=`echo $line | cut -d: -f2`
		user_name=`echo $line | cut -d: -f1`
		if [ $user_name != "/root" ]
		then
			IFS=$'\012'
			for file in `IFS=$OLDIFS;find "$user_home" $find_options ! -user root ! -user  $user_name  `
			do
				writeAndLog "STRANGE : $file does not belongs to $user_name, why is it in $user_home?"
			done | sort
			for file in `IFS=$OLDIFS;find "$user_home" $find_options -user root ! -user   $user_name `
			do
				writeAndLog "STRANGE|DANGER : $file  belongs to root, why is it in $user_home?"
			done | sort
			for file in `IFS=$OLDIFS;find / $find_options -type l -maxdepth 8 ! -user root  2>/dev/null`
			do
				[[ "$file" =~ ^/dev ]] || [[ "$file" =~ ^/proc ]] || [[ "$file" =~ ^/lib/udev ]] || ! stat -L "$file" &>/dev/null ||
				{
					[  "$(stat --format=%u "$file" 2>/dev/null)" = "$(stat -L --format=%u "$file" 2>/dev/null)" ] || writeAndLog "NORMAL|RISK : $file is a symbolic link that do not have the same owner as its targeting file."
				}
			done | sort
		fi
	done
	IFS=$'\012'
	for file in `IFS=$OLDIFS;find  /tmp $find_options  -type l  `
	do
		writeAndLog "RISK : $file is a symbolic link inside the /tmp folder"
	done | sort
	for file in `IFS=$OLDIFS;find  /var/tmp $find_options  -type l  `
	do
		if [ "$file" != "/var/tmp" ]
		then
			writeAndLog "RISK : $file is a symbolic link inside the /var/tmp folder"
		fi
	done | sort
	for file in `IFS=$OLDIFS;find  /home $find_options ! -type l  -perm -002  `
	do
		writeAndLog "RISK : $file is world writeable, is it normal?"
	done | sort
	for file in `IFS=$OLDIFS;find   /home $find_options ! -type l  -perm -4000  `
	do
		writeAndLog "RISK : $file is setuid, is it normal?"
	done | sort
	for file in `IFS=$OLDIFS;find    /home $find_options ! -type l  -perm -2000  `
	do
		writeAndLog "RISK : $file is setgid, is it normal?"
	done | sort
fi


IFS=$'\012'
for file in `IFS=$OLDIFS;find / $find_options -name "-*" `
do
	writeAndLog "RISK : $file is named like a flag, no file should." # See http://h.ackack.net/flag-execution-for-easy-local-privilege-escalation.html
done
for file in `IFS=$OLDIFS;find  /var $find_options ! -type l ! -type c ! -type s  -perm -002  `
do
	if [ "$file" != "/var/lock" ] && [ "$file" != "/var/crash" ]&& [ "$file" != "/var/tmp" ] && [ "$file" != "/var/spool/postfix/public/pickup" ] \
&&  [ "$file" != "/var/spool/postfix/public/qmgr" ]
	then
		writeAndLog "NORMAL|DANGER : $file is world writeable, most files in /var shouldn't be, but some have to. In doubt, verify."
	fi
done | sort

IFS=$OLDIFS
ww_scan_dirs="/bin /sbin /boot /etc /lib /root /usr "
for ww_scan_dir in $ww_scan_dirs
do
	IFS=$'\012'
	for file in `IFS=$OLDIFS; find $ww_scan_dir $find_options  ! -type l  -perm -002 `
	do
		writeAndLog "DANGER : $file is world writeable, files in $ww_scan_dir shouldn't be."
	done | sort
done
unset ww_scan_dir
unset ww_scan_dirs
IFS=$'\012'
for file in `IFS=$OLDIFS; find / $find_options  -type d -perm -002 ! -perm -1000   2>/dev/null`
do
	writeAndLog "DANGER : $file is a world writeable directory, it should have the sticky byte on."
done | sort

IFS=$OLDIFS
blacklistFiles="/dev/tcp /dev/udp"
for blacklistFile in $blacklistFiles
do
	[ -e "$blacklistFile" ] && writeAndLog "DANGER : $blacklistFile is a security hole, remove if you can."
done
unset blacklistFile
unset blacklistFiles

IFS=$'\012'
for file in `IFS=$OLDIFS;find / $find_options -nouser  2>/dev/null`
do
	writeAndLog "DANGER : No user corresponds to $file  numeric user ID."
done | sort
for file in `IFS=$OLDIFS;find / $find_options  -nogroup  2>/dev/null`
do
	writeAndLog "DANGER : No group corresponds to $file  numeric group ID."
done | sort
for file in `IFS=$OLDIFS;find /root $find_options ! -user root  2>/dev/null`
do
	writeAndLog "DANGER : $file doesn't belong to root. It musn't be in the /root folder."
done | sort
IFS=$OLDIFS
device_scan_dirs="/bin /sbin /lib /boot /etc /home /root /sys /usr /var /tmp /mnt /media /proc"
for device_scan_dir in $device_scan_dirs
do
	IFS=$'\012'
	for file in `IFS=$OLDIFS;find $device_scan_dir $find_options -type b -o -type c  2>/dev/null`
	do
		[[ "$file" =~ ^/lib/udev/devices/ ]] || writeAndLog "DANGER : $file is a device and should be in /dev (or /lib/udev/devices)."
	done | sort
done
unset device_scan_dir
unset device_scan_dirs
IFS=$'\012'
for file in `IFS=$OLDIFS; find  /root $find_options ! -type l  -perm -002  `
do
	writeAndLog "EXTREME DANGER : $file is world writeable, musn't be the case in /root folder."
done | sort
for file in `IFS=$OLDIFS; find   /tmp $find_options  -perm -4000  `
do
	writeAndLog "EXTREME DANGER : $file is setuid and shouldn't be in /tmp folder."
done | sort
for file in `IFS=$OLDIFS; find   /tmp $find_options  -perm -2000  `
do
	writeAndLog "EXTREME DANGER : $file is setgid and shouldn't be in /tmp folder."
done | sort
if [ -d /var/tmp ]
then
	for file in `IFS=$OLDIFS; find   /var/tmp $find_options  -perm -4000  `
	do
		writeAndLog "EXTREME DANGER : $file is setuid and shouldn't be in /var/tmp folder."
	done | sort
fi
for file in `IFS=$OLDIFS; find   /var/tmp $find_options  -perm -2000  `
do
	writeAndLog "EXTREME DANGER : $file is setgid and shouldn't be in /var/tmp folder."
done | sort
for file in `IFS=$OLDIFS; find   / $find_options -perm -4002  2>/dev/null`
do
	writeAndLog "EXTREME DANGER : $file is setuid and world writeable."
done | sort
for file in `IFS=$OLDIFS; find   / $find_options -perm  -2002  2>/dev/null`
do
	writeAndLog "EXTREME DANGER : $file is setgid and world writeable."
done | sort
IFS=$OLDIFS
nonReadeableFiles="/etc/master.passwd /etc/shadow /etc/shadow- /etc/gshadow /etc/sudoers /var/log/messages "
for nonReadeableFile in $nonReadeableFiles
do
	[ -f "$nonReadeableFile" ] && [[ $(ls -gn "$nonReadeableFile") =~ ^.......r..\ .*$ ]]  &&  writeAndLog "EXTREME DANGER : $nonReadeableFile should not be readeable by others."
done
unset nonReadeableFile
unset nonReadeableFiles

####################################### Superuser file capabilities scanning #####################################

[ $CAPABILITIES ] &&
{

	# NOTE getcap -r seems to have difficulties to run on partitionned filesystems
	# NOTE getcap -r seems to bug on symlink and/or large files
	mountedFilesystems=""
	totalCaps=$(find / -type f -print0 2>/dev/null  |  xargs -0 getcap   2>/dev/null)
	writeAndLog "*** Linux file capabilities scan ***."
	writeAndLog "Number of files with capabilities : $(echo "$totalCaps" | wc -l)"
	IFS=$'\012'
	dangerousCaps="cap_chown cap_dac_override cap_fowner cap_module cap_sys_admin cap_setuid cap_setfcap"
	for line in $totalCaps
	do
		IFS=$OLDIFS
		for  dangerousCap in  $dangerousCaps
		do
			[[ "$line" =~ ^.*=\ .*$dangerousCap ]] && writeAndLog "RISK : $(echo "$line" | cut -d "=" -f 1) has or inherits the $dangerousCap capability"
		done
		{ [[ "$line" =~ ^.*=ep ]] || [[ "$line" =~ ^.*=eip ]] || [[ "$line" =~ ^.*=ei ]]; } && writeAndLog "DANGER : $(echo "$line" | cut -d "=" -f 1) has or inherits all capabilities"
		IFS=$'\012'
	done
	unset line
	unset dangerousCaps
	unset dangerousCap

	# scan folder where there shouldn't be any capable file
	for line in $totalCaps
	do
		IFS=$OLDIFS
		for noCapsDir in `echo "/boot /dev /etc /home /proc /root /tmp /var"`
		do
			[[ "$line" =~ ^$noCapsDir ]] && writeAndLog "DANGER :  $(echo "$line" | cut -d "=" -f 1) has capabilities, files in $noCapsDir shouldn't."
		done
		IFS=$'\012'
	done
	unset noCapsDir
	# Find world writeable capable files
	for line in $totalCaps
	do
		file="$(echo $line |  sed -r 's/^(.*) =.*/\1/')"
		[[ "$(stat --format=%A "$file")" =~ ^.*.w.$ ]] && writeAndLog "EXTREME DANGER : $file has capabilities and is world writeable."
	done
	unset line
	unset file
	# Find non root owner capable files
	for line in $totalCaps
	do
		file="$(echo $line |  sed -r 's/^(.*) =.*/\1/')"
		[ "$(stat --format=%u "$file")" != 0 ] && writeAndLog "EXTREME DANGER : $file has capabilities and does not belong to root."
	done
	unset line
	unset file
}
IFS=$OLDIFS
unset OLDIFS
echo
exit 0
