#!/usr/bin/env bash # Do not edit this file directly, this file is generated from the files # in the src directory. Any updates to this file will be overwritten when generated # sanitize the environment before run [ "$(env | /bin/sed -r -e '/^(PWD|SHLVL|_)=/d')" ] && exec -c "$0" "$@" # --- Modified Version --- # Name : checksec.sh # Version : 1.7.0 # Author : Brian Davis # Date : Feburary 2014 # Download: https://github.com/slimm609/checksec.sh # # --- Modified Version --- # Name : checksec.sh # Version : based on 1.5 # Author : Robin David # Date : October 2013 # Download: https://github.com/RobinDavid/checksec # # --- Original version --- # Name : checksec.sh # Version : 1.5 # Author : Tobias Klein # Date : November 2011 # Download: http://www.trapkit.de/tools/checksec.html # Changes : http://www.trapkit.de/tools/checksec_changes.txt # The BSD License (http://www.opensource.org/licenses/bsd-license.php) # specifies the terms and conditions of use for checksec.sh: # Copyright (c) 2014-2015, Brian Davis # Copyright (c) 2013, Robin David # Copyright (c) 2009-2011, Tobias Klein # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # * Neither the name of Tobias Klein nor the name of trapkit.de may be # used to endorse or promote products derived from this software # without specific prior written permission. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # set global lang to C export LC_ALL="C" # version SCRIPT_VERSION=2021101001 SCRIPT_MAJOR=2 SCRIPT_MINOR=5 SCRIPT_REVISION=0 # global vars debug=false verbose=false format="cli" SCRIPT_NAME="checksec" SCRIPT_URL="https://github.com/slimm609/checksec.sh/raw/master/${SCRIPT_NAME}" SIG_URL="https://github.com/slimm609/checksec.sh/raw/master/$(basename ${SCRIPT_NAME} .sh).sig" pkg_release=false commandsmissing=false OPT=0 extended_checks=false # FORTIFY_SOURCE vars FS_end=_chk FS_cnt_total=0 FS_cnt_checked=0 FS_cnt_unchecked=0 FS_libc=0 if [[ $(id -u) != 0 ]]; then export PATH=${PATH}:/sbin/:/usr/sbin/ fi # check if directory exists dir_exists() { if [[ -d "${1}" ]]; then return 0 else return 1 fi } # check user privileges root_privs() { if [[ $(/usr/bin/id -u) -eq 0 ]]; then return 0 else return 1 fi } # check for required files and deps first # check if command exists command_exists() { type "${1}" > /dev/null 2>&1 } for command in cat awk sed sysctl uname mktemp openssl grep stat file find sort head ps readlink basename id which xargs; do if ! (command_exists ${command}); then echo >&2 -e "\e[31mWARNING: '${command}' not found! It's required for most checks.\e[0m" commandsmissing=true fi done if [[ ${commandsmissing} == true ]]; then echo >&2 -e "\n\e[31mWARNING: Not all necessary commands found. Some tests might not work!\e[0m\n" sleep 2 fi if (command_exists readelf); then readelf="readelf -W" elif (command_exists eu-readelf); then readelf="eu-readelf -W" elif (command_exists greadelf); then readelf="greadelf -W" else echo -e "\n\e[31mERROR: readelf is a required tool for almost all tests. Aborting...\e[0m\n" exit fi sysarch=$(uname -m) if [[ "${sysarch}" == "x86_64" ]]; then arch="64" elif [[ "${sysarch}" == "i?86" ]]; then arch="32" elif [[ "${sysarch}" =~ "arm" ]]; then arch="arm" elif [[ "${sysarch}" =~ "aarch64" ]]; then arch="aarch64" fi # check for system-wide ASLR support aslrcheck() { # PaX ASLR support if ! (grep -q 'Name:' /proc/1/status 2> /dev/null); then echo_message '\033[33m insufficient privileges for PaX ASLR checks\033[m\n' '' '' '' echo_message ' Fallback to standard Linux ASLR check' '' '' '' fi if grep -q 'PaX:' /proc/1/status 2> /dev/null; then if grep -q 'PaX:' /proc/1/status 2> /dev/null | grep -q 'R'; then echo_message '\033[32mPaX ASLR enabled\033[m\n\n' '' '' '' else echo_message '\033[31mPaX ASLR disabled\033[m\n\n' '' '' '' fi else # standard Linux 'kernel.randomize_va_space' ASLR support # (see the kernel file 'Documentation/sysctl/kernel.txt' for a detailed description) echo_message " (kernel.randomize_va_space): " '' '' '' if sysctl -a 2> /dev/null | grep -q 'kernel.randomize_va_space = 1'; then echo_message '\033[33mPartial (Setting: 1)\033[m\n\n' '' '' '' echo_message " Description - Make the addresses of mmap base, stack and VDSO page randomized.\n" '' '' '' echo_message " This, among other things, implies that shared libraries will be loaded to \n" '' '' '' echo_message " random addresses. Also for PIE-linked binaries, the location of code start\n" '' '' '' echo_message " is randomized. Heap addresses are *not* randomized.\n\n" '' '' '' elif sysctl -a 2> /dev/null | grep -q 'kernel.randomize_va_space = 2'; then echo_message '\033[32mFull (Setting: 2)\033[m\n\n' '' '' '' echo_message " Description - Make the addresses of mmap base, heap, stack and VDSO page randomized.\n" '' '' '' echo_message " This, among other things, implies that shared libraries will be loaded to random \n" '' '' '' echo_message " addresses. Also for PIE-linked binaries, the location of code start is randomized.\n\n" '' '' '' elif sysctl -a 2> /dev/null | grep -q 'kernel.randomize_va_space = 0'; then echo_message '\033[31mNone (Setting: 0)\033[m\n' '' '' '' else echo_message '\033[31mNot supported\033[m\n' '' '' '' fi echo_message " See the kernel file 'Documentation/sysctl/kernel.txt' for more details.\n\n" '' '' '' fi } chk_dir() { if [[ -z "${CHK_DIR}" ]]; then printf "\033[31mError: Please provide a valid directory.\033[m\n\n" exit 1 fi # follow symlink if [[ -L "${CHK_DIR}" ]]; then CHK_DIR=$(readlink -f "${CHK_DIR}") fi # remove trailing slashes tempdir=$(echo "${CHK_DIR}" | sed -e "s/\/*$//") if [[ ! -d "${tempdir}" ]]; then printf "\033[31mError: The directory '%s' does not exist.\033[m\n\n" "${tempdir}" exit 1 fi if ${extended_checks}; then echo_message "RELRO STACK CANARY NX PIE SELFRANDO Clang CFI SafeStack RPATH RUNPATH Symbols \tFORTIFY\tFortified\tFortifiable Filename\n" '' "\n" "{ \"dir\": { \"name\":\"$tempdir\" }" else echo_message "RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols \tFORTIFY\tFortified\tFortifiable Filename\n" '' "\n" "{ \"dir\": { \"name\":\"$tempdir\" }" fi fdircount=0 fdirtotal=0 while read -r N; do if [[ "${N}" != "[A-Za-z1-0]*" ]]; then out=$(file "$(readlink -f "${N}")") if [[ ${out} =~ ELF ]]; then ((fdirtotal++)) fi fi done < <(find "${tempdir}" -type f 2> /dev/null) if [[ $fdirtotal -gt 0 ]]; then echo_message "" "" "" "," fi while read -r N; do if [[ "${N}" != "[A-Za-z1-0]*" ]]; then # read permissions? if [[ ! -r "${N}" ]]; then printf "\033[31mError: No read permissions for '%s' (run as root).\033[m\n" ", ${N}" else # ELF executable? out=$(file "$(readlink -f "${N}")") if [[ ! ${out} =~ ELF ]]; then if [[ "${verbose}" = "true" ]]; then echo_message "\033[34m*** Not an ELF file: ${tempdir}/" "" "" "" file "${N}" echo_message "\033[m" "" "" "" fi else ((fdircount++)) echo_message "" "" " " "" filecheck "${N}" if [[ "$(find "${N}" \( -perm -004000 -o -perm -002000 \) -type f -print)" ]]; then echo_message "\033[37;41m${N}\033[m\n" ",${N}\n" " filename='${N}' />\n" ", \"filename\":\"${N}\"}" else echo_message "${N}\n" ",${N}\n" " filename='${N}' />\n" ", \"filename\":\"${N}\"}" fi if [[ "${fdircount}" == "${fdirtotal}" ]]; then echo_message "" "" "" "" else echo_message "" "" "" "," fi fi fi fi done < <(find "${tempdir}" -type f 2> /dev/null) echo_message "" "" "\n" "}" } chk_file() { if [[ -z "${CHK_FILE}" ]]; then printf "\033[31mError: Please provide a valid file.\033[m\n\n" exit 1 fi # does the file exist? if [[ ! -e "${CHK_FILE}" ]]; then printf "\033[31mError: The file '%s' does not exist.\033[m\n\n" "${CHK_FILE}" exit 1 fi # read permissions? if [[ ! -r "${CHK_FILE}" ]]; then printf "\033[31mError: No read permissions for '%s' (run as root).\033[m\n\n" "${CHK_FILE}" exit 1 fi # ELF executable? out=$(file "$(readlink -f "${CHK_FILE}")") if [[ ! ${out} =~ ELF ]]; then printf "\033[31mError: Not an ELF file: " file "${CHK_FILE}" printf "\033[m\n" exit 1 fi if ${extended_checks}; then echo_message "RELRO STACK CANARY NX PIE SELFRANDO Clang CFI SafeStack RPATH RUNPATH\tSymbols\t\tFORTIFY\tFortified\tFortifiable\tFILE\n" '' '' '{' else echo_message "RELRO STACK CANARY NX PIE RPATH RUNPATH\tSymbols\t\tFORTIFY\tFortified\tFortifiable\tFILE\n" '' '' '{' fi filecheck "${CHK_FILE}" if [[ "$(find "${CHK_FILE}" \( -perm -004000 -o -perm -002000 \) -type f -print)" ]]; then echo_message "\033[37;41m${CHK_FILE}\033[m\n" ",${CHK_FILE}\n" " filename='${CHK_FILE}'/>\n" " } }" else echo_message "${CHK_FILE}\n" ",${CHK_FILE}\n" " filename='${CHK_FILE}'/>\n" " } }" fi } chk_file_list() { if ${extended_checks}; then echo_message "RELRO STACK CANARY NX PIE SELFRANDO Clang CFI SafeStack RPATH RUNPATH\tSymbols\t\tFORTIFY\tFortified\tFortifiable\tFILE\n" '' '' '{\n' else echo_message "RELRO STACK CANARY NX PIE RPATH RUNPATH\tSymbols\t\tFORTIFY\tFortified\tFortifiable\tFILE\n" '' '' '{\n' fi while IFS="" read -r p || [[ -n "${p}" ]]; do CHK_FILE="${p}" if [[ -z "${CHK_FILE}" ]]; then printf "\033[31mError: Please provide a valid file.\033[m\n\n" exit 1 fi # does the file exist? if [[ ! -e "${CHK_FILE}" ]]; then printf "\033[31mError: The file '%s' does not exist.\033[m\n\n" "${CHK_FILE}" exit 1 fi # read permissions? if [[ ! -r "${CHK_FILE}" ]]; then printf "\033[31mError: No read permissions for '%s' (run as root).\033[m\n\n" "${CHK_FILE}" exit 1 fi # ELF executable? out=$(file "$(readlink -f "${CHK_FILE}")") if [[ ! ${out} =~ ELF ]]; then printf "\033[31mError: Not an ELF file: " file "${CHK_FILE}" printf "\033[m\n" exit 1 fi filecheck "${CHK_FILE}" if [[ "$(find "${CHK_FILE}" \( -perm -004000 -o -perm -002000 \) -type f -print)" ]]; then echo_message "\033[37;41m${CHK_FILE}\033[m\n" ",${CHK_FILE}\n" " filename='${CHK_FILE}'/>\n" " } }" else echo_message "${CHK_FILE}\n" ",${CHK_FILE}\n" " filename='${CHK_FILE}'/>\n" " },\n" fi done < "${CHK_FILE_LIST}" echo_message '' '' '' ' }\n' } chk_fortify_file() { # if first char of pathname is '~' replace it with '${HOME}' if [[ "${CHK_FORTIFY_FILE:0:1}" = '~' ]]; then CHK_FORTIFY_FILE=${HOME}/${CHK_FORTIFY_FILE:1} fi if [[ -z "${CHK_FORTIFY_FILE}" ]]; then printf "\033[31mError: Please provide a valid file.\033[m\n\n" exit 1 fi # does the file exist? if [[ ! -f "${CHK_FORTIFY_FILE}" ]]; then printf "\033[31mError: The file '%s' does not exist.\033[m\n\n" "${CHK_FORTIFY_FILE}" exit 1 fi # read permissions? if [[ ! -r "${CHK_FORTIFY_FILE}" ]]; then printf "\033[31mError: No read permissions for '%s' (run as root).\033[m\n\n" "${CHK_FORTIFY_FILE}" exit 1 fi # ELF executable? out=$(file "$(readlink -f "${CHK_FORTIFY_FILE}")") if [[ ! ${out} =~ ELF ]]; then printf "\033[31mError: Not an ELF file: " file "${CHK_FORTIFY_FILE}" printf "\033[m\n" exit 1 fi if [[ -e /lib/libc.so.6 ]]; then FS_libc=/lib/libc.so.6 elif [[ -e /lib64/libc.so.6 ]]; then FS_libc=/lib64/libc.so.6 elif [[ -e /lib/i386-linux-gnu/libc.so.6 ]]; then FS_libc=/lib/i386-linux-gnu/libc.so.6 elif [[ -e /lib/x86_64-linux-gnu/libc.so.6 ]]; then FS_libc=/lib/x86_64-linux-gnu/libc.so.6 elif [[ -e /lib/arm-linux-gnueabihf/libc.so.6 ]]; then FS_libc=/lib/arm-linux-gnueabihf/libc.so.6 elif [[ -e /lib/aarch64-linux-gnu/libc.so.6 ]]; then FS_libc=/lib/aarch64-linux-gnu/libc.so.6 else printf "\033[31mError: libc not found.\033[m\n\n" exit 1 fi FS_chk_func_libc=() FS_functions=() while IFS='' read -r line; do FS_chk_func_libc+=("$line"); done < <(${readelf} -s ${FS_libc} 2> /dev/null | grep _chk@@ | awk '{ print $8 }' | cut -c 3- | sed -e 's/_chk@.*//') while IFS='' read -r line; do FS_functions+=("$line"); done < <(${readelf} -s "${CHK_FORTIFY_FILE}" 2> /dev/null | awk '{ print $8 }' | sed 's/_*//' | sed -e 's/@.*//') echo_message "" "" "\n" "} }" } chk_fortify_proc() { if [[ -z "${CHK_FORTIFY_PROC}" ]]; then printf "\033[31mError: Please provide a valid process ID.\033[m\n\n" exit 1 fi if ! (isNumeric "${CHK_FORTIFY_PROC}"); then printf "\033[31mError: Please provide a valid process ID.\033[m\n\n" exit 1 fi cd /proc || exit N=${CHK_FORTIFY_PROC} if [[ -d "${N}" ]]; then # read permissions? if [[ ! -r "${N}/exe" ]]; then if ! (root_privs); then printf "\033[31mNo read permissions for '/proc/%s/exe' (run as root).\033[m\n\n" "${N}" exit 1 fi if [[ ! "$(readlink "${N}/exe")" ]]; then printf "\033[31mPermission denied. Requested process ID belongs to a kernel thread.\033[m\n\n" exit 1 fi exit 1 fi if [[ -e /lib/libc.so.6 ]]; then FS_libc=/lib/libc.so.6 elif [[ -e /lib64/libc.so.6 ]]; then FS_libc=/lib64/libc.so.6 elif [[ -e /lib/i386-linux-gnu/libc.so.6 ]]; then FS_libc=/lib/i386-linux-gnu/libc.so.6 elif [[ -e /lib/x86_64-linux-gnu/libc.so.6 ]]; then FS_libc=/lib/x86_64-linux-gnu/libc.so.6 else printf "\033[31mError: libc not found.\033[m\n\n" exit 1 fi name=$(head -1 "${N}/status" | cut -b 7-) echo_message "* Process name (PID) : ${name} (${N})\n" "" "" "" FS_chk_func_libc=() FS_functions=() while IFS='' read -r line; do FS_chk_func_libc+=("$line"); done < <(${readelf} -s $FS_libc 2> /dev/null | grep _chk@@ | awk '{ print $8 }' | cut -c 3- | sed -e 's/_chk@.*//') while IFS='' read -r line; do FS_functions+=("$line"); done < <(${readelf} -s "${CHK_FORTIFY_PROC}/exe" 2> /dev/null | awk '{ print $8 }' | sed 's/_*//' | sed -e 's/@.*//') echo_message "" "" "\n" "} }" fi } chk_proc_all() { cd /proc || exit echo_message "* System-wide ASLR" "" "" "" aslrcheck echo_message "* Does the CPU support NX: " "" "" "" nxcheck echo_message "* Core-Dumps access to all users: " "" "" "" coredumpcheck if ${extended_checks}; then echo_message " COMMAND PID RELRO STACK CANARY Clang CFI SafeStack SECCOMP NX/PaX PIE SELFRANDO FORTIFY\n" "" "" '{' else echo_message " COMMAND PID RELRO STACK CANARY SECCOMP NX/PaX PIE FORTIFY\n" "" "" '{' fi lastpid=0 currpid=0 for N in [1-9]*; do if [[ "${N}" != "$$" ]] && readlink -q "${N}"/exe > /dev/null; then ((lastpid++)) fi done for N in [1-9]*; do if [[ "${N}" != "$$" ]] && readlink -q "${N}"/exe > /dev/null; then ((currpid++)) name=$(head -1 "${N}"/status | cut -b 7-) if [[ $format == "cli" ]]; then printf "%16s" "${name}" printf "%7d " "${N}" else echo_message "" "${N}," " \n" "" else echo_message "\n" "\n" "\n" "," fi fi done echo_message "" "" "" " }\n" if [[ ! -e /usr/bin/id ]]; then echo_message "\n\033[33mNote: If you are running 'checksec.sh' as an unprivileged user, you\n" "" "" "" echo_message " will not see all processes. Please run the script as root.\033[m\n\n" "" "" "\n" else if ! (root_privs); then echo_message "\n\033[33mNote: You are running 'checksec.sh' as an unprivileged user.\n" "" "" "" echo_message " Too see all processes, please run the script as root.\033[m\n\n" "" "" "\n" fi fi } chk_proc() { if [[ -z "${CHK_PROC}" ]]; then printf "\033[31mError: Please provide a valid process name.\033[m\n\n" exit 1 fi cd /proc || exit if (isString "${CHK_PROC}"); then IFS=" " read -r -a fpids <<< "$(pgrep -d ' ' "${CHK_PROC}")" elif (isNumeric "${CHK_PROC}"); then fpids=("${CHK_PROC}") else printf "\033[31mError: Please provide a valid process name or pid.\033[m\n\n" exit 1 fi if [[ ${#fpids} -eq 0 ]]; then printf "\033[31mError: No process with the given name or pid found.\033[m\n\n" exit 1 fi echo_message "* System-wide ASLR" '' '' '' aslrcheck echo_message "* Does the CPU support NX: " '' '' '' nxcheck if ${extended_checks}; then echo_message " COMMAND PID RELRO STACK CANARY Clang CFI SafeStack SECCOMP NX/PaX PIE SELFRANDO FORTIFY\n" "" "" '{' else echo_message " COMMAND PID RELRO STACK CANARY SECCOMP NX/PaX PIE FORTIFY\n" "" "" '{' fi pos=$((${#fpids[*]} - 1)) last=${fpids[$pos]} for N in "${fpids[@]}"; do if [[ -d "${N}" ]]; then name=$(head -1 "${N}"/status | cut -b 7-) if [[ $format == "cli" ]]; then printf "%16s" "${name}" printf "%7d " "${N}" else echo_message "" "${N}," "\n" "" else echo_message "\n" "\n" "\n" "," fi fi done echo_message "\n" "\n" "\n" "}\n" } chk_proc_libs() { if [[ -z "${CHK_PROC_LIBS}" ]]; then printf "\033[31mError: Please provide a valid process ID.\033[m\n\n" exit 1 fi if ! (isNumeric "${CHK_PROC_LIBS}"); then printf "\033[31mError: Please provide a valid process ID.\033[m\n\n" exit 1 fi cd /proc || exit echo_message "* System-wide ASLR" '' '' '' aslrcheck echo_message "* Does the CPU support NX: " '' '' '' nxcheck echo_message "* Process information:\n\n" "" "" "" if ${extended_checks}; then echo_message " COMMAND PID RELRO STACK CANARY Clang CFI SafeStack SECCOMP NX/PaX PIE Fortify Source\n" '' '' '' else echo_message " COMMAND PID RELRO STACK CANARY SECCOMP NX/PaX PIE Fortify Source\n" '' '' '' fi N=${CHK_PROC_LIBS} if [[ -d "${N}" ]]; then name=$(head -1 "${N}/status" | cut -b 7-) if [[ "${format}" == "cli" ]]; then printf "%16s" "${name}" printf "%7d " "${N}" else echo_message "" "${name}," "\n" "} } }" fi } #Check core dumps restricted? coredumpcheck() { coreValue=$(grep -Exic "hard[[:blank:]]+core[[:blank:]]+0" /etc/security/limits.conf) coreValueDefault=$(grep -Exic "\*[[:blank:]]+hard[[:blank:]]+core[[:blank:]]+0" /etc/security/limits.conf) dumpableValue=$(sysctl -b -e fs.suid_dumpable) if { [[ "${coreValue}" == 1 ]] || [[ "${coreValueDefault}" == 1 ]]; } && { [[ "${dumpableValue}" == 0 ]] || [[ "${dumpableValue}" == 2 ]]; }; then echo_message '\033[32mRestricted\033[m\n\n' '' '' '' else echo_message '\033[31mNot Restricted\033[m\n\n' '' '' '' fi } debug_report() { echo "***** Checksec debug *****" failed=false id uname -a echo "checksec version: ${SCRIPT_MAJOR}.${SCRIPT_MINOR}.${SCRIPT_REVISION} -- ${SCRIPT_VERSION}" if [[ -f /etc/os-release ]]; then # freedesktop.org and systemd # shellcheck disable=SC1091 source /etc/os-release # shellcheck disable=SC2153 OS=${NAME} VER=${VERSION_ID} elif type lsb_release > /dev/null 2>&1; then # linuxbase.org OS=$(lsb_release -si) VER=$(lsb_release -sr) elif [[ -f /etc/lsb-release ]]; then # For some versions of Debian/Ubuntu without lsb_release command # shellcheck disable=SC1091 source /etc/lsb-release OS=${DISTRIB_ID} VER=${DISTRIB_RELEASE} elif [[ -f /etc/debian_version ]]; then # Older Debian/Ubuntu/etc. OS=Debian VER=$(cat /etc/debian_version) elif [[ -f /etc/SuSe-release ]]; then # Older SuSE/etc. OS=$(cat /etc/SuSe-release) VER=$(uname -r) elif [[ -f /etc/redhat-release ]]; then # Older Red Hat, CentOS, etc. OS=$(cat /etc/redhat-release) VER=$(uname -r) else # Fall back to uname, e.g. "Linux ", also works for BSD, etc. OS=$(uname -s) VER=$(uname -r) fi echo "OS=${OS}" echo "VER=${VER}" for command in cat awk sysctl uname mktemp openssl grep stat file find head ps readlink basename id which wget curl readelf eu-readelf; do path="$(command -v ${command})" if [[ -e "${path}" ]]; then ls -l "${path}" if [[ -L "${path}" ]]; then absolutepath=$(readlink -f "${path}") ls -l "${absolutepath}" file "${absolutepath}" else file "${path}" fi else echo "*** can not find command ${command}" failed=true fi done if [[ ${failed} ]]; then exit 1 fi } # check file(s) filecheck() { # check for RELRO support if ${readelf} -l "${1}" 2> /dev/null | grep -q 'GNU_RELRO'; then if ${readelf} -d "${1}" 2> /dev/null | grep -q 'BIND_NOW'; then echo_message '\033[32mFull RELRO \033[m ' 'Full RELRO,' ' /dev/null | grep -Eq '__stack_chk_fail|__stack_chk_guard|__intel_security_cookie'; then echo_message '\033[32mCanary found \033[m ' 'Canary found,' ' canary="yes"' '"canary":"yes",' else echo_message '\033[31mNo canary found\033[m ' 'No Canary found,' ' canary="no"' '"canary":"no",' fi # check for NX support if ${readelf} -l "${1}" 2> /dev/null | grep -q 'GNU_STACK'; then if ${readelf} -l "${1}" 2> /dev/null | grep 'GNU_STACK' | grep -q 'RWE'; then echo_message '\033[31mNX disabled\033[m ' 'NX disabled,' ' nx="no"' '"nx":"no",' else echo_message '\033[32mNX enabled \033[m ' 'NX enabled,' ' nx="yes"' '"nx":"yes",' fi else echo_message '\033[31mNX disabled\033[m ' 'NX disabled,' ' nx="no"' '"nx":"no",' fi # check for PIE support if ${readelf} -h "${1}" 2> /dev/null | grep -q 'Type:[[:space:]]*EXEC'; then echo_message '\033[31mNo PIE \033[m ' 'No PIE,' ' pie="no"' '"pie":"no",' elif ${readelf} -h "${1}" 2> /dev/null | grep -q 'Type:[[:space:]]*DYN'; then if ${readelf} -d "${1}" 2> /dev/null | grep -q 'DEBUG'; then echo_message '\033[32mPIE enabled \033[m ' 'PIE enabled,' ' pie="yes"' '"pie":"yes",' else echo_message '\033[33mDSO \033[m ' 'DSO,' ' pie="dso"' '"pie":"dso",' fi elif ${readelf} -h "${1}" 2> /dev/null | grep -q 'Type:[[:space:]]*REL'; then echo_message '\033[33mREL \033[m ' 'REL,' ' pie="rel"' '"pie":"rel",' else echo_message '\033[33mNot an ELF file\033[m ' 'Not an ELF file,' ' pie="not_elf"' '"pie":"not_elf",' fi if ${extended_checks}; then # check for selfrando support if ${readelf} -S "${1}" 2> /dev/null | grep -c txtrp | grep -q '1'; then echo_message '\033[32mSelfrando enabled \033[m ' else echo_message '\033[31mNo Selfrando \033[m ' fi fi if ${extended_checks}; then # check if compiled with Clang CFI #if $readelf -s "$1" 2>/dev/null | grep -Eq '\.cfi'; then read -r cfifunc <<< "$($readelf -s "${1}" 2> /dev/null | grep .cfi | awk '{ print $8 }')" func=${cfifunc/.cfi/} if [ -n "$cfifunc" ] && $readelf -s "$1" 2> /dev/null | grep -q "$func$"; then echo_message '\033[32mClang CFI found \033[m ' 'with CFI,' ' clangcfi="yes"' '"clangcfi":"yes",' else echo_message '\033[31mNo Clang CFI found\033[m ' 'without CFI,' ' clangcfi="no"' '"clangcfi":"no",' fi # check if compiled with Clang SafeStack if $readelf -s "$1" 2> /dev/null | grep -Eq '__safestack_init'; then echo_message '\033[32mSafeStack found \033[m ' 'with SafeStack,' ' safestack="yes"' '"safestack":"yes",' else echo_message '\033[31mNo SafeStack found\033[m ' 'without SafeStack,' ' safestack="no"' '"safestack":"no",' fi fi # check for rpath / run path # search for a line that matches RPATH and extract the colon-separated path list within brackets # example input: "0x000000000000000f (RPATH) Library rpath: [/lib/systemd:/lib/apparmor]" IFS=: read -r -a rpath_array <<< "$(${readelf} -d "${1}" 2> /dev/null | awk -F'[][]' '/RPATH/ {print $2}')" if [[ "${#rpath_array[@]}" -gt 0 ]]; then if xargs stat -c %A <<< "${rpath_array[*]}" 2> /dev/null | grep -q 'rw'; then echo_message '\033[31mRW-RPATH \033[m ' 'RPATH,' ' rpath="yes"' '"rpath":"yes",' else echo_message '\033[31mRPATH \033[m ' 'RPATH,' ' rpath="yes"' '"rpath":"yes",' fi else echo_message '\033[32mNo RPATH \033[m ' 'No RPATH,' ' rpath="no"' '"rpath":"no",' fi # search for a line that matches RUNPATH and extract the colon-separated path list within brackets IFS=: read -r -a runpath_array <<< "$(${readelf} -d "${1}" 2> /dev/null | awk -F'[][]' '/RUNPATH/ {print $2}')" if [[ "${#runpath_array[@]}" -gt 0 ]]; then if xargs stat -c %A <<< "${runpath_array[*]}" 2> /dev/null | grep -q 'rw'; then echo_message '\033[31mRW-RUNPATH \033[m ' 'RUNPATH,' ' runpath="yes"' '"runpath":"yes",' else echo_message '\033[31mRUNPATH \033[m ' 'RUNPATH,' ' runpath="yes"' '"runpath":"yes",' fi else echo_message '\033[32mNo RUNPATH \033[m ' 'No RUNPATH,' ' runpath="no"' '"runpath":"no",' fi # check for stripped symbols in the binary IFS=" " read -r -a SYM_cnt <<< "$(${readelf} --symbols "${1}" 2> /dev/null | grep '\.symtab' | cut -d' ' -f5 | cut -d: -f1))" if ${readelf} --symbols "${1}" 2> /dev/null | grep -q '\.symtab'; then echo_message "\033[31m${SYM_cnt[0]} Symbols\t\033[m " 'Symbols,' ' symbols="yes"' '"symbols":"yes",' else echo_message '\033[32mNo Symbols\t\033[m ' 'No Symbols,' ' symbols="no"' '"symbols":"no",' fi # check for FORTIFY SOURCE if [[ -e /lib/libc.so.6 ]]; then FS_libc=/lib/libc.so.6 elif [[ -e /lib/libc.so.7 ]]; then FS_libc=/lib/libc.so.7 elif [[ -e /lib/libc.so ]]; then FS_libc=/lib/libc.so elif [[ -e /lib64/libc.so.6 ]]; then FS_libc=/lib64/libc.so.6 elif [[ -e /lib/i386-linux-gnu/libc.so.6 ]]; then FS_libc=/lib/i386-linux-gnu/libc.so.6 elif [[ -e /lib/x86_64-linux-gnu/libc.so.6 ]]; then FS_libc=/lib/x86_64-linux-gnu/libc.so.6 elif [[ -e /lib/arm-linux-gnueabihf/libc.so.6 ]]; then FS_libc=/lib/arm-linux-gnueabihf/libc.so.6 elif [[ -e /lib/aarch64-linux-gnu/libc.so.6 ]]; then FS_libc=/lib/aarch64-linux-gnu/libc.so.6 elif [[ -e /usr/x86_64-gentoo-linux-musl/bin/ld ]]; then FS_libc=/usr/x86_64-gentoo-linux-musl/bin/ld else printf "\033[31mError: libc not found.\033[m\n\n" exit 1 fi FS_filechk_func_libc="$(${readelf} -s $FS_libc 2> /dev/null | sed -ne 's/.*__\(.*_chk\)@@.*/\1/p')" FS_func_libc="${FS_filechk_func_libc//_chk/}" FS_func="$(${readelf} --dyn-syms "${1}" 2> /dev/null | awk '{ print $8 }' | sed -e 's/_*//' -e 's/@.*//' -e '/^$/d')" FS_cnt_checked=$(grep -cFxf <(sort <<< "${FS_filechk_func_libc}") <(sort <<< "${FS_func}")) FS_cnt_unchecked=$(grep -cFxf <(sort <<< "${FS_func_libc}") <(sort <<< "${FS_func}")) FS_cnt_total=$((FS_cnt_unchecked + FS_cnt_checked)) if grep -q '_chk$' <<< "$FS_func"; then echo_message '\033[32mYes\033[m' 'Yes,' ' fortify_source="yes" ' '"fortify_source":"yes",' else echo_message "\033[31mNo\033[m" "No," ' fortify_source="no" ' '"fortify_source":"no",' fi echo_message "\t${FS_cnt_checked}\t" "${FS_cnt_checked}", "fortified=\"${FS_cnt_checked}\" " "\"fortified\":\"${FS_cnt_checked}\"," echo_message "\t${FS_cnt_total}\t\t" "${FS_cnt_total}" "fortify-able=\"${FS_cnt_total}\"" "\"fortify-able\":\"${FS_cnt_total}\"" } # format format() { list="cli csv xml json" if [[ -n "${output_format}" ]]; then if [[ ! ${list} =~ ${output_format} ]]; then printf "\033[31mError: Please provide a valid format {cli, csv, xml, json}.\033[m\n\n" exit 1 fi fi if [[ "${output_format}" == "xml" ]]; then echo '' fi format="${output_format}" } # --- FORTIFY_SOURCE subfunctions (start) --- # is FORTIFY_SOURCE supported by libc? FS_libc_check() { echo_message "* FORTIFY_SOURCE support available (libc) : " "" "" if [[ "${#FS_chk_func_libc[@]}" != "0" ]]; then echo_message "\033[32mYes\033[m\n" "Yes," " libc_fortify_source='yes' " ', "libc_fortify_source":"yes"' else echo_message "\033[31mNo\033[m\n" "No," " libc_fortify_source='no' " ', "libc_fortify_source":"no"' exit 1 fi } # was the binary compiled with FORTIFY_SOURCE? FS_binary_check() { echo_message "* Binary compiled with FORTIFY_SOURCE support: " "" "" "" for ((FS_elem_functions = 0; FS_elem_functions < ${#FS_functions[@]}; FS_elem_functions++)); do if [[ ${FS_functions[$FS_elem_functions]} =~ _chk$ ]]; then echo_message "\033[32mYes\033[m\n" "Yes\n" " binary_compiled_with_fortify='yes'>\n" ', "binary_compiled_with_fortify":"yes"' return fi done echo_message "\033[31mNo\033[m\n" "No\n" " binary_compiled_with_fortify='no'>\n" ', "binary_compiled_with_fortify":"no"' } FS_comparison() { echo_message "\n" "" "" echo_message " ------ EXECUTABLE-FILE ------- . -------- LIBC --------\n" "" "" "" echo_message " Fortifiable library functions | Checked function names\n" "" "" "" echo_message " -------------------------------------------------------\n" "" "" "" for ((FS_elem_libc = 0; FS_elem_libc < ${#FS_chk_func_libc[@]}; FS_elem_libc++)); do for ((FS_elem_functions = 0; FS_elem_functions < ${#FS_functions[@]}; FS_elem_functions++)); do FS_tmp_func=${FS_functions[$FS_elem_functions]} FS_tmp_libc=${FS_chk_func_libc[$FS_elem_libc]} if [[ ${FS_tmp_func} =~ ^${FS_tmp_libc}$ ]]; then if [[ ${format} == "cli" ]]; then printf " \033[31m%-30s\033[m | __%s%s\n" "${FS_tmp_func}" "${FS_tmp_libc}" "${FS_end}" else if [[ $FS_elem_functions == 0 ]]; then echo_message "" "${FS_tmp_func},${FS_tmp_libc},yes\n" " \n" ", \"function\": { \"name\":\"${FS_tmp_func}\", \"libc\":\"${FS_tmp_libc}\", \"fortifiable\":\"yes\" }" elif [[ $FS_elem_functions == $((${#FS_functions[@]} - 1)) ]]; then echo_message "" "${FS_tmp_func},${FS_tmp_libc},yes\n" " \n" ", \"function\": { \"name\":\"${FS_tmp_func}\", \"libc\":\"${FS_tmp_libc}\", \"fortifiable\":\"yes\" }" else echo_message "" "${FS_tmp_func},${FS_tmp_libc},yes\n" " \n" ", \"function\": { \"name\":\"${FS_tmp_func}\", \"libc\":\"${FS_tmp_libc}\", \"fortifiable\":\"yes\" }" fi fi ((FS_cnt_total++)) ((FS_cnt_unchecked++)) elif [[ ${FS_tmp_func} =~ ^${FS_tmp_libc}(_chk)$ ]]; then if [[ ${format} == "cli" ]]; then printf " \033[32m%-30s\033[m | __%s%s\n" "${FS_tmp_func}" "${FS_tmp_libc}" "${FS_end}" else if [[ $FS_elem_functions == 0 ]]; then echo_message "" "${FS_tmp_func},${FS_tmp_libc},no\n" " \n" ", \"function\": { \"name\":\"${FS_tmp_func}\", \"libc\":\"${FS_tmp_libc}\", \"fortifiable\":\"no\" }" elif [[ $FS_elem_functions == $((${#FS_functions[@]} - 1)) ]]; then echo_message "" "${FS_tmp_func},${FS_tmp_libc},no\n" " \n" ", \"function\": { \"name\":\"${FS_tmp_func}\", \"libc\":\"${FS_tmp_libc}\", \"fortifiable\":\"no\" }" else echo_message "" "${FS_tmp_func},${FS_tmp_libc},no\n" " \n" ", \"function\": { \"name\":\"${FS_tmp_func}\", \"libc\":\"${FS_tmp_libc}\", \"fortifiable\":\"no\" }" fi fi ((FS_cnt_total++)) ((FS_cnt_checked++)) fi done done } FS_summary() { echo_message "\n" "" "\n" "" echo_message "SUMMARY:\n\n" "" "" "" echo_message "* Number of checked functions in libc : ${#FS_chk_func_libc[@]}\n" "${#FS_chk_func_libc[@]}," " " ", \"nb_unchecked_func\":\"${FS_cnt_unchecked}\" } " echo_message "\n" "\n" "\n" "" } echo_message() { if [[ ${format} == "csv" ]]; then echo -n -e "$2" elif [[ ${format} == "xml" ]]; then echo -n -e "$3" elif [[ ${format} == "json" ]]; then echo -n -e "$4" else #default to cli echo -n -e "${1}" fi } # check if input is numeric isNumeric() { echo "$@" | grep -q -v "[^0-9]" } # check if input is a string isString() { echo "$@" | grep -q -v "[^ A-Z_a-z]" } # help help() { echo "Usage: checksec [--format={cli,csv,xml,json}] [OPTION]" echo echo echo "Options:" echo echo " ## Checksec Options" echo " --file={file}" echo " --dir={directory}" echo " --listfile={text file with one file per line}" echo " --proc={process name}" echo " --proc-all" echo " --proc-libs={process ID}" echo " --kernel[=kconfig]" echo " --fortify-file={executable-file}" echo " --fortify-proc={process ID}" echo " --version" echo " --help" if ! ${pkg_release}; then echo " --update or --upgrade" fi echo echo " ## Modifiers" echo " --debug" echo " --verbose" echo " --format={cli,csv,xml,json}" echo " --output={cli,csv,xml,json}" echo " --extended" echo echo "For more information, see:" echo " http://github.com/slimm609/checksec.sh" echo } chk_kernel() { if [[ ${CHK_KERNEL} == "kernel" ]]; then CHK_KERNEL="" fi if [[ -e "${CHK_KERNEL}" ]] && [[ ! -d "${CHK_KERNEL}" ]]; then if [[ -s "$(pwd -P)/${CHK_KERNEL}" ]]; then configfile=$(pwd -P)/${CHK_KERNEL} elif [[ -s "${CHK_KERNEL}" ]]; then configfile=${CHK_KERNEL} else "Error: config file specified do not exist" exit 1 fi echo_message "* Kernel protection information for : $configfile \n\n" "" "" "" cd /proc && kernelcheck "$configfile" || exit else cd /proc || exit echo_message "* Kernel protection information:\n\n" "" "" "" kernelcheck fi } # check selinux status getsestatus() { local status if (command_exists getenforce); then sestatus=$(getenforce) if [[ "${sestatus}" == "Disabled" ]]; then status=0 elif [[ "${sestatus}" == "Permissive" ]]; then status=1 elif [[ "${sestatus}" == "Enforcing" ]]; then status=2 fi elif (command_exists sestatus); then sestatus=$(sestatus | grep "SELinux status" | awk '{ print $3}') if [[ "${sestatus}" == "disabled" ]]; then status=0 elif [[ "${sestatus}" == "enabled" ]]; then sestatus2=$(sestatus | grep "Current" | awk '{ print $3}') if [[ "${sestatus2}" == "permissive" ]]; then status=1 elif [[ "${sestatus2}" == "enforcing" ]]; then status=2 fi fi fi return ${status} } # check for kernel protection mechanisms kernelcheck() { echo_message " Description - List the status of kernel protection mechanisms. Rather than\n" '' '' '' echo_message " inspect kernel mechanisms that may aid in the prevention of exploitation of\n" '' '' '' echo_message " userspace processes, this option lists the status of kernel configuration\n" '' '' '' echo_message " options that harden the kernel itself against attack.\n\n" '' '' '' echo_message " Kernel config:\n" '' '' '{ "kernel": ' if [[ ! "${1}" == "" ]]; then kconfig="cat ${1}" echo_message " Warning: The config ${1} on disk may not represent running kernel config!\n\n" "${1}" "" '{ "KernelConfig":"not_found" } }' exit 0 fi echo_message " Vanilla Kernel ASLR: " "" "" "" randomize_va=$(sysctl -b -e kernel.randomize_va_space) if [[ "${randomize_va}" == "2" ]]; then echo_message "\033[32mFull\033[m\n" "Full," " randomize_va_space='full'" ', "randomize_va_space":"full"' elif [[ "${randomize_va}" == "1" ]]; then echo_message "\033[33mPartial\033[m\n" "Partial," " randomize_va_space='partial'" ', "randomize_va_space":"partial"' else echo_message "\033[31mNone\033[m\n" "None," " randomize_va_space='none'" ', "randomize_va_space":"none"' fi echo_message " NX protection: " "" "" "" if (command_exists journalctl); then nx_protection=$(journalctl -kb -o cat | grep -Fw NX | head -n 1) elif (command_exists dmesg) && (root_privs); then nx_protection=$(dmesg -t 2> /dev/null | grep -Fw NX) fi if [ -n "$nx_protection" ]; then if [[ "${nx_protection}" == "NX (Execute Disable) protection: active" ]]; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " nx_protection='yes'" ', "nx_protection":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " nx_protection='no'" ', "nx_protection":"no"' fi else echo_message "\033[33mSkipped\033[m\n" "Skipped," " nx_protection='skipped'" ', "nx_protection":"skipped"' fi echo_message " Protected symlinks: " "" "" "" symlink=$(sysctl -b -e fs.protected_symlinks) if [[ "${symlink}" == "1" ]]; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " protect_symlinks='yes'" ', "protect_symlinks":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " protect_symlinks='no'" ', "protect_symlinks":"no"' fi echo_message " Protected hardlinks: " "" "" "" hardlink=$(sysctl -b -e fs.protected_hardlinks) if [[ "${hardlink}" == "1" ]]; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " protect_hardlinks='yes'" ', "protect_hardlinks":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " protect_hardlinks='no'" ', "protect_hardlinks":"no"' fi echo_message " Protected fifos: " "" "" "" fifos=$(sysctl -b -e fs.protected_fifos) if [[ -z "${fifos}" ]]; then echo_message "\033[33mUnsupported\033[m\n" "Unsupported," " protect_fifos='unsupported'" ', "protect_fifos":"unsupported"' elif [[ "${fifos}" == "1" ]]; then echo_message "\033[33mPartial\033[m\n" "Partial," " protect_fifos='partial'" ', "protect_fifos":"partial"' elif [[ "${fifos}" == "2" ]]; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " protect_fifos='yes'" ', "protect_fifos":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " protect_fifos='no'" ', "protect_fifos":"no"' fi echo_message " Protected regular: " "" "" "" regular=$(sysctl -b -e fs.protected_regular) if [[ -z "${regular}" ]]; then echo_message "\033[33mUnsupported\033[m\n" "Unsupported," " protect_regular='unsupported'" ', "protect_regular":"unsupported"' elif [[ "${regular}" == "1" ]]; then echo_message "\033[33mPartial\033[m\n" "Partial," " protect_regular='partial'" ', "protect_regular":"partial"' elif [[ "${regular}" == "2" ]]; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " protect_regular='yes'" ', "protect_regular":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " protect_regular='no'" ', "protect_regular":"no"' fi echo_message " Ipv4 reverse path filtering: " "" "" "" ipv4_rpath=$(sysctl -b -e net.ipv4.conf.all.rp_filter) if [[ "${ipv4_rpath}" == "1" ]]; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " ipv4_rpath='yes'" ', "ipv4_rpath":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " ipv4_rpath='no'" ', "ipv4_rpath":"no"' fi echo_message " Kernel heap randomization: " "" "" "" # NOTE: y means it turns off kernel heap randomization for backwards compatability (libc5) if ${kconfig} | grep -qi 'CONFIG_COMPAT_BRK=y'; then echo_message "\033[31mDisabled\033[m\n" "Disabled," " kernel_heap_randomization='no'" ', "kernel_heap_randomization":"no"' else echo_message "\033[32mEnabled\033[m\n" "Enabled," " kernel_heap_randomization='yes'" ', "kernel_heap_randomization":"yes"' fi if ${kconfig} | grep -qi 'CONFIG_CC_STACKPROTECTOR' || ${kconfig} | grep -qa 'CONFIG_STACKPROTECTOR'; then echo_message " GCC stack protector support: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_CC_STACKPROTECTOR=y' || ${kconfig} | grep -qi 'CONFIG_STACKPROTECTOR=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " gcc_stack_protector='yes'" ', "gcc_stack_protector":"yes"' if ${kconfig} | grep -qi 'CONFIG_CC_STACKPROTECTOR_STRONG' || ${kconfig} | grep -qi 'CONFIG_STACKPROTECTOR_STRONG'; then echo_message " GCC stack protector strong: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_CC_STACKPROTECTOR_STRONG=y' || ${kconfig} | grep -qi 'CONFIG_STACKPROTECTOR_STRONG=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " gcc_stack_protector_strong='yes'" ', "gcc_stack_protector_strong":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " gcc_stack_protector_strong='no'" ', "gcc_stack_protector_strong":"no"' fi fi else echo_message "\033[31mDisabled\033[m\n" "Disabled," " gcc_stack_protector='no'" ', "gcc_stack_protector":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_GCC_PLUGIN_STRUCTLEAK'; then echo_message " GCC structleak plugin: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_GCC_PLUGIN_STRUCTLEAK=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " gcc_structleak='yes'" ', "gcc_structleak":"yes"' echo_message " GCC structleak by ref plugin: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " gcc_structleak_byref='yes'" ', "gcc_structleak_byref":"yes"' else echo_message "\033[32mEnabled\033[m\n" "Enabled," " gcc_structleak_byref='no'" ', "gcc_structleak_byref":"no"' fi else echo_message "\033[31mDisabled\033[m\n" "Disabled," " gcc_structleak='no'" ', "gcc_structleak":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_SLAB_FREELIST_RANDOM'; then echo_message " SLAB freelist randomization: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_SLAB_FREELIST_RANDOM=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " slab_freelist_randomization='yes'" ', "slab_freelist_randomization":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " slab_freelist_randomization='no'" ', "slab_freelist_randomization":"no"' fi fi if ${kconfig} | grep -qi 'CPU_SW_DOMAIN_PAN=y'; then echo_message " Use CPU domains: " "" "" "" if ${kconfig} | grep -qi 'CPU_SW_DOMAIN_PAN=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " cpu_sw_domain'yes'" ', "cpu_sw_domain":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " cpu_sw_domain='no'" ', "cpu_sw_domain":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_VMAP_STACK'; then echo_message " Virtually-mapped kernel stack: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_VMAP_STACK=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " virtually_mapped_stack='yes'" ', "virtually_mapped_stack":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " virtually_mapped_stack='no'" ', "virtually_mapped_stack":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_STRICT_DEVMEM'; then echo_message " Restrict /dev/mem access: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_STRICT_DEVMEM=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " restrict_dev_mem_access='yes'" ', "restrict_dev_mem_access":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " restrict_dev_mem_access='no'" ', "restrict_dev_mem_access":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_IO_STRICT_DEVMEM'; then echo_message " Restrict I/O access to /dev/mem: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_IO_STRICT_DEVMEM=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " restrict_io_dev_mem_access='yes'" ', "restrict_io_dev_mem_access":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " restrict_io_dev_mem_access='no'" ', "restrict_io_dev_mem_access":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_REFCOUNT_FULL'; then echo_message " Full reference count validation: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_REFCOUNT_FULL=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " full_refcount_validation='yes'" ', "full_refcount_validation":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " full_refcount_validation='no'" ', "full_refcount_validation":"no"' fi fi echo_message " Exec Shield: " """" "" execshield=$(sysctl -b -e kernel.exec-shield) if [[ -z "${execshield}" ]]; then echo_message '\033[32mUnsupported\033[m\n\n' '' '' '' elif [[ "${execshield}" == "1" ]]; then echo_message '\033[32mEnabled\033[m\n\n' '' '' '' else echo_message '\033[31mDisabled\033[m\n\n' '' '' '' fi if ${kconfig} | grep -qi 'CONFIG_HARDENED_USERCOPY'; then echo_message " Hardened Usercopy: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_HARDENED_USERCOPY=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " hardened_usercopy='yes'" ', "hardened_usercopy":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " hardened_usercopy='no'" ', "hardened_usercopy":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_FORTIFY_SOURCE'; then echo_message " Harden str/mem functions: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_FORTIFY_SOURCE=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " fortify_source='yes'" ', "fortify_source":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " fortify_source='no'" ', "fortify_source":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_DEVKMEM'; then echo_message " Restrict /dev/kmem access: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_DEVKMEM=y'; then echo_message "\033[31mDisabled\033[m\n" "Disabled," " restrict_dev_kmem_access='no'" ', "restrict_dev_kmem_access":"no"' else echo_message "\033[32mEnabled\033[m\n" "Enabled," " restrict_dev_kmem_access='yes'" ', "restrict_dev_kmem_access":"yes"' fi fi #x86 only if [[ "${arch}" == "32" ]] || [[ "${arch}" == "64" ]]; then echo_message "\n" "\n" "" "" echo_message "* X86 only: \n" "" "" "" if ! ${kconfig} | grep -qi 'CONFIG_PAX_SIZE_OVERFLOW=y'; then if ${kconfig} | grep -qi 'CONFIG_DEBUG_STRICT_USER_COPY_CHECKS'; then echo_message " Strict user copy checks: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " strict_user_copy_check='yes'" ', "strict_user_copy_check":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " strict_user_copy_check='no'" ', "strict_user_copy_check":"no"' fi fi fi if ${kconfig} | grep -qi 'CONFIG_RANDOMIZE_BASE' || ${kconfig} | grep -qi 'CONFIG_PAX_ASLR'; then echo_message " Address space layout randomization: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_RANDOMIZE_BASE=y' || ${kconfig} | grep -qi 'CONFIG_PAX_ASLR=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " random_address_space_layout='yes'" ', "random_address_space_layout":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " random_address_space_layout='no'" ', "random_address_space_layout":"no"' fi fi fi #ARM only if [[ "${arch}" == "arm" ]]; then echo_message "\n" "\n" "\n" "" echo_message "* ARM only: \n" "" "" "" if ${kconfig} | grep -qi 'CONFIG_ARM_KERNMEM_PERMS'; then echo_message " Restrict kernel memory permissions: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_ARM_KERNMEM_PERMS=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " arm_kernmem_perms='yes'" ', "arm_kernmem_perms":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " arm_kernmem_perms='no'" ', "arm_kernmem_perms":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_DEBUG_ALIGN_RODATA'; then echo_message " Make rodata strictly non-excutable: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_DEBUG_ALIGN_RODATA=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " arm_strict_rodata='yes'" ', "arm_strict_rodata":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " arm_strict_rodata='no'" ', "arm_strict_rodata":"no"' fi fi fi #ARM64 only if [[ "${arch}" == "aarch64" ]]; then echo_message "\n" "\n" "\n" "" echo_message "* ARM64 only: \n" "" "" "" if ${kconfig} | grep -qi 'CONFIG_UNMAP_KERNEL_AT_EL0'; then echo_message " Unmap kernel in userspace (KAISER): " "" "" "" if ${kconfig} | grep -qi 'CONFIG_UNMAP_KERNEL_AT_EL0=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " unmap_kernel_in_userspace='yes'" ', "unmap_kernel_in_userspace":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " unmap_kernel_in_userspace='no'" ', "unmap_kernel_in_userspace":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_HARDEN_BRANCH_PREDICTOR'; then echo_message " Harden branch predictor: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_HARDEN_BRANCH_PREDICTOR=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " harden_branch_predictor='yes'" ', "harden_branch_predictor":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " harden_branch_predictor='no'" ', "harden_branch_predictor":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_HARDEN_EL2_VECTORS'; then echo_message " Harden EL2 vector mapping: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_HARDEN_EL2_VECTORS=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " harden_el2_vector_mapping='yes'" ', "harden_el2_vector_mapping":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " harden_el2_vector_mapping='no'" ', "harden_el2_vector_mapping":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_ARM64_SSBD'; then echo_message " Speculative store bypass disable: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_ARM64_SSBD=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " speculative_store_bypass_disable='yes'" ', "speculative_store_bypass_disable":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " speculative_store_bypass_disable='no'" ', "speculative_store_bypass_disable":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_ARM64_SW_TTBR0_PAN'; then echo_message " Emulate privileged access never: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_ARM64_SW_TTBR0_PAN=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " emulate_privileged_access_never='yes'" ', "emulate_privileged_access_never":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " emulate_privileged_access_never='no'" ', "emulate_privileged_access_never":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_RANDOMIZE_BASE'; then echo_message " Randomize address of kernel image: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_RANDOMIZE_BASE=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " randomize_kernel_address='yes'" ', "randomize_kernel_address":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " randomize_kernel_address='no'" ', "randomize_kernel_address":"no"' fi fi if ${kconfig} | grep -qi 'CONFIG_RANDOMIZE_MODULE_REGION_FULL'; then echo_message " Randomize module region over 4GB: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_RANDOMIZE_MODULE_REGION_FULL=y'; then echo_message "\033[32mEnabled\033[m\n" "Enabled," " randomize_module_region_full='yes'" ', "randomize_module_region_full":"yes"' else echo_message "\033[31mDisabled\033[m\n" "Disabled," " randomize_module_region_full='no'" ', "randomize_module_region_full":"no"' fi fi fi echo_message "" "" ">" "}," echo_message "\n" "\n" "\n" "" echo_message "* SELinux: " "" "" "" if ${kconfig} | grep -qi 'CONFIG_SECURITY_SELINUX=y'; then getsestatus sestatus=$? if [[ ${sestatus} == 0 ]]; then echo_message "\033[31mDisabled\033[m\n" "Disabled,," " \n\n" " }}" } # check mapped libraries libcheck() { IFS=" " read -r -a libs <<< "$(awk '{ print $6 }' "/proc/${1}/maps" | grep '/' | sort -u | xargs file | grep ELF | awk '{ print $1 }' | sed 's/:/ /')" echo_message "\n* Loaded libraries (file information, # of mapped files: ${#libs[@]}):\n\n" "" "" "\"libs\": {" for ((element = 0; element < ${#libs[@]}; element++)); do echo_message " ${libs[$element]}:\n" "${libs[$element]}," "" "" echo_message " " "" " " "" filecheck "${libs[$element]}" if [[ ${element} == $((${#libs[@]} - 1)) ]]; then echo_message "\n\n" "\n" " filename='${libs[$element]}' />\n" "" else echo_message "\n\n" "\n" " filename='${libs[$element]}' />\n" "}," fi done } # check cpu nx flag nxcheck() { if grep -qFw nx /proc/cpuinfo; then echo_message '\033[32mYes\033[m\n\n' '' '' '' else echo_message '\033[31mNo\033[m\n\n' '' '' '' fi } # check process(es) proccheck() { # check for RELRO support if ${readelf} -l "${1}/exe" 2> /dev/null | grep -q 'Program Headers'; then if ${readelf} -l "${1}/exe" 2> /dev/null | grep -q 'GNU_RELRO'; then if ${readelf} -d "${1}/exe" 2> /dev/null | grep -q 'BIND_NOW'; then echo_message '\033[32mFull RELRO \033[m ' 'Full RELRO,' ' relro="full"' '"relro":"full",' else echo_message '\033[33mPartial RELRO\033[m ' 'Partial RELRO,' ' relro="partial"' '"relro":"partial",' fi else echo_message '\033[31mNo RELRO \033[m ' 'No RELRO,' ' relro="no"' '"relro":"no",' fi else echo -n -e '\033[31mPermission denied (please run as root)\033[m\n' exit 1 fi # check for stack canary support if ${readelf} -s "${1}/exe" 2> /dev/null | grep -q 'Symbol table'; then if ${readelf} -s "${1}/exe" 2> /dev/null | grep -Eq '__stack_chk_fail|__stack_chk_guard|__intel_security_cookie'; then echo_message '\033[32mCanary found \033[m ' 'Canary found,' ' canary="yes"' '"canary":"yes",' else echo_message '\033[31mNo canary found \033[m ' 'No Canary found,' ' canary="no"' '"canary":"no",' fi else if [[ "${1}" == "1" ]]; then echo_message '\033[33mPermission denied \033[m ' 'Permission denied,' ' canary="Permission denied"' '"canary":"Permission denied",' else echo_message '\033[33mNo symbol table found \033[m ' 'No symbol table found,' ' canary="No symbol table found"' '"canary":"No symbol table found",' fi fi if ${extended_checks}; then # check if compiled with Clang CFI $debug && echo -e "\n***function proccheck->clangcfi" #if $readelf -s "$1" 2>/dev/null | grep -Eq '\.cfi'; then read -r -a cfifunc <<< "$($readelf -s "$1/exe" 2> /dev/null | grep .cfi | awk '{ print $8 }')" func=${cfifunc/.cfi/} # TODO: fix this check properly, need more clang CFI files to be able to test properly # shellcheck disable=SC2128 if [ -n "$cfifunc" ] && $readelf -s "$1/exe" 2> /dev/null | grep -q "$func$"; then echo_message '\033[32mClang CFI found \033[m ' 'with CFI,' ' clangcfi="yes"' '"clangcfi":"yes",' else echo_message '\033[31mNo Clang CFI found\033[m ' 'without CFI,' ' clangcfi="no"' '"clangcfi":"no",' fi # check if compiled with Clang SafeStack $debug && echo -e "\n***function proccheck->safestack" if $readelf -s "$1/exe" 2> /dev/null | grep -Eq '__safestack_init'; then echo_message '\033[32mSafeStack found \033[m ' 'with SafeStack,' ' safestack="yes"' '"safestack":"yes",' else echo_message '\033[31mNo SafeStack found\033[m ' 'without SafeStack,' ' safestack="no"' '"safestack":"no",' fi fi # check for Seccomp mode seccomp=$(grep 'Seccomp:' "${1}/status" 2> /dev/null | cut -b10) if [[ "${seccomp}" == "1" ]]; then echo_message '\033[32mSeccomp strict\033[m ' 'Seccomp strict,' ' seccomp="strict"' '"seccomp":"strict",' elif [[ "${seccomp}" == "2" ]]; then echo_message '\033[32mSeccomp-bpf \033[m ' 'Seccomp-bpf,' ' seccomp="bpf"' '"seccomp":"bpf",' else echo_message '\033[31mNo Seccomp \033[m ' 'No Seccomp,' ' seccomp="no"' '"seccomp":"no",' fi # first check for PaX support if grep -q 'PaX:' "${1}/status" 2> /dev/null; then pageexec=$(grep 'PaX:' "${1}/status" 2> /dev/null | cut -b6) segmexec=$(grep 'PaX:' "${1}/status" 2> /dev/null | cut -b10) mprotect=$(grep 'PaX:' "${1}/status" 2> /dev/null | cut -b8) randmmap=$(grep 'PaX:' "${1}/status" 2> /dev/null | cut -b9) if [[ "${pageexec}" = "P" || "${segmexec}" = "S" ]] && [[ "${mprotect}" = "M" && "${randmmap}" = "R" ]]; then echo_message '\033[32mPaX enabled\033[m ' 'Pax enabled,' ' pax="yes"' '"pax":"yes",' elif [[ "${pageexec}" = "p" && "${segmexec}" = "s" && "${randmmap}" = "R" ]]; then echo_message '\033[33mPaX ASLR only\033[m ' 'Pax ASLR only,' ' pax="aslr_only"' '"pax":"aslr_only",' elif [[ "${pageexec}" = "P" || "${segmexec}" = "S" ]] && [[ "${mprotect}" = "m" && "${randmmap}" = "R" ]]; then echo_message '\033[33mPaX mprot off \033[m' 'Pax mprot off,' ' pax="mprot_off"' '"pax":"mprot_off",' elif [[ "${pageexec}" = "P" || "${segmexec}" = "S" ]] && [[ "${mprotect}" = "M" && "${randmmap}" = "r" ]]; then echo_message '\033[33mPaX ASLR off\033[m ' 'Pax ASLR off,' ' pax="aslr_off"' '"pax":"aslr_off",' elif [[ "${pageexec}" = "P" || "${segmexec}" = "S" ]] && [[ "${mprotect}" = "m" && "${randmmap}" = "r" ]]; then echo_message '\033[33mPaX NX only\033[m ' 'Pax NX only,' ' pax="nx_only"' '"pax":"nx_only",' else echo_message '\033[31mPaX disabled\033[m ' 'Pax disabled,' ' pax="no"' '"pax":"no",' fi # fallback check for NX support elif ${readelf} -l "${1}/exe" 2> /dev/null | grep 'GNU_STACK' | grep -q 'RWE'; then echo_message '\033[31mNX disabled\033[m ' 'NX disabled,' ' nx="no"' '"nx":"no",' else echo_message '\033[32mNX enabled \033[m ' 'NX enabled,' ' pax="yes"' '"nx":"yes",' fi # check for PIE support if ${readelf} -h "${1}/exe" 2> /dev/null | grep -q 'Type:[[:space:]]*EXEC'; then echo_message '\033[31mNo PIE \033[m ' 'No PIE,' ' pie="no"' '"pie":"no",' elif ${readelf} -h "${1}/exe" 2> /dev/null | grep -q 'Type:[[:space:]]*DYN'; then if ${readelf} -d "${1}/exe" 2> /dev/null | grep -q 'DEBUG'; then echo_message '\033[32mPIE enabled \033[m ' 'PIE enabled,' ' pie="yes"' '"pie":"yes",' else echo_message '\033[33mDynamic Shared Object\033[m ' 'Dynamic Shared Object,' ' pie="dso"' '"pie":"dso",' fi else echo_message '\033[33mNot an ELF file \033[m ' 'Not an ELF file,' ' pie="not_elf"' '"pie":"not_elf",' fi if ${extended_checks}; then # check for selfrando support if ${readelf} -S "${1}/exe" 2> /dev/null | grep -c txtrp | grep -q '1'; then echo_message '\033[32mSelfrando enabled \033[m ' else echo_message '\033[31mNo Selfrando \033[m ' fi fi #check for forifty source support Proc_FS_functions="$(${readelf} -s "${1}/exe" 2> /dev/null | awk '{ print $8 }' | sed 's/_*//' | sed -e 's/@.*//')" if grep -q '_chk$' <<< "$Proc_FS_functions"; then echo_message '\033[32mYes\033[m' 'Yes' " fortify_source='yes'>" '"fortify_source":"yes" }' else echo_message "\033[31mNo\033[m" "No" " fortify_source='no'>" '"fortify_source":"no" }' fi } #openssl public key for verification of updates read -r PUBKEY << EOF LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF3Z25kcnk2WGJpNE8wR2w1T2UzSQp1eWRyMlZqR1hteDJFM0thd0wrK1F3a2FVT0RHOEVuT24weFZ1S1ZkZEphZjY3Rmxzd3pPYjh1RFRDTjdsWURnCnFKQXdmNllTOUFsdU5RRmlFQWhFRlgxL0dsMi9TSnFHYXhFVU9HTlV3NTI5a3BVR0MwNmN6SHhENEcvdWNBQlkKT05iWm9Vc1pIYmRnZUNueWs1dzZ0SWs3MEplNmZ2em5Da2JxbUZhS0UyQnhWTERLU0liSDBTak5XT3RSMmF6ZAp1V3p2RU1kVXFlZlZjYXErUDFjV0dLNy94VllSNkV3ME1aQTdWU0xkREhlRUVySW9Kc3UvM2VaeUR5ZDlaUlJvCmdpajM2R1N2SFREclU1ZVdXRlN0Q01UM29DRDhMSjVpbXBReWpWd3Z5M3Z4ZVNVYzVkdytZUDU0OU9jNHF2bzYKOXdJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg== EOF # Update/Upgrade # shellcheck disable=SC2120 upgrade() { if ${pkg_release}; then printf "\033[31mError: Unknown option '%s'.\033[m\n\n" "${1}" help exit 1 fi umask 027 TMP_FILE=$(mktemp /tmp/checksec.XXXXXXXXXX) SIG_FILE=$(mktemp /tmp/checksec_sig.XXXXXXXX) PUBKEY_FILE=$(mktemp /tmp/checksec_pubkey.XXXXXXXXXX) fetch "${SCRIPT_URL}" "${TMP_FILE}" fetch "${SIG_URL}" "${SIG_FILE}" echo "${PUBKEY}" | base64 -d > "${PUBKEY_FILE}" if ! openssl dgst -sha256 -verify "${PUBKEY_FILE}" -signature "${SIG_FILE}" "${TMP_FILE}" > /dev/null 2>&1; then echo "file signature does not match. Update may be tampered" rm -f "${TMP_FILE}" "${SIG_FILE}" "${PUBKEY_FILE}" > /dev/null 2>&1 exit 1 fi UPDATE_VERSION=$(grep "^SCRIPT_VERSION" "${TMP_FILE}" | awk -F"=" '{ print $2 }') if [[ "${SCRIPT_VERSION}" != "${UPDATE_VERSION}" ]]; then PERMS=$(stat -c "%a" "$0") rm -f "${SIG_FILE}" "${PUBKEY_FILE}" > /dev/null 2>&1 mv "${TMP_FILE}" "$0" > /dev/null 2>&1 exit_status=$? if [[ "${exit_status}" -eq "0" ]]; then echo "checksec.sh updated - Rev. ${UPDATE_VERSION}" chmod "${PERMS}" "${0}" else echo "Error: Could not update... Please check permissions" rm -f "${TMP_FILE}" > /dev/null 2>&1 exit 1 fi else echo "checksec.sh not updated... Already on latest version" rm -f "${TMP_FILE}" "${SIG_FILE}" "${PUBKEY_FILE}" > /dev/null 2>&1 exit 1 fi exit 0 } # Version compare vercomp() { if [[ "${1}" == "${2}" ]]; then return 0 fi local IFS=. local i ver1="${1}" ver2="${2}" # fill empty fields in ver1 with zeros for ((i = ${#ver1[@]}; i < ${#ver2[@]}; i++)); do ver1[i]=0 done for ((i = 0; i < ${#ver1[@]}; i++)); do if [[ -z ${ver2[i]} ]]; then # fill empty fields in ver2 with zeros ver2[i]=0 fi if ((10#${ver1[i]} > 10#${ver2[i]})); then return 1 fi if ((10#${ver1[i]} < 10#${ver2[i]})); then return 2 fi done return 0 } # Fetch the update fetch() { if type wget > /dev/null 2>&1; then wget --no-check-certificate -O "${2}" "${1}" > /dev/null 2>&1 elif type curl > /dev/null 2>&1; then curl --insecure --remote-name -o "${2}" "${1}" > /dev/null 2>&1 else echo 'Warning: Neither wget nor curl is available. online updates unavailable' >&2 exit 1 fi } # version information version() { echo "checksec v${SCRIPT_MAJOR}.${SCRIPT_MINOR}.${SCRIPT_REVISION}, Brian Davis, github.com/slimm609/checksec.sh, Dec 2015" echo "Based off checksec v1.5, Tobias Klein, www.trapkit.de, November 2011" echo } # run help if nothing is passed if [[ $# -lt 1 ]]; then help exit 1 fi optspec=":h-:" while getopts "${optspec}" optchar; do case "${optchar}" in -) case "${OPTARG}" in version) version exit 0 ;; debug) debug=true ;; trace) export BASH_XTRACEFD=5 export PS4='(${BASH_SOURCE##*/}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' set -x ;; help) help exit 0 ;; debug_report) debug_report exit 0 ;; update | upgrade) # shellcheck disable=SC2119 upgrade exit 0 ;; format=* | output=*) output_format=${OPTARG#*=} format ;; verbose) verbose=true ;; extended) extended_checks=true ;; dir=*) CHK_DIR=${OPTARG#*=} OPT=$((OPT + 1)) CHK_FUNCTION="chk_dir" ;; file=*) CHK_FILE=${OPTARG#*=} OPT=$((OPT + 1)) CHK_FUNCTION="chk_file" ;; listfile=*) CHK_FILE_LIST=${OPTARG#*=} OPT=$((OPT + 1)) CHK_FUNCTION="chk_file_list" ;; proc-all) OPT=$((OPT + 1)) CHK_FUNCTION="chk_proc_all" ;; proc=*) CHK_PROC=${OPTARG#*=} OPT=$((OPT + 1)) CHK_FUNCTION="chk_proc" ;; proc-libs=*) CHK_PROC_LIBS=${OPTARG#*=} OPT=$((OPT + 1)) CHK_FUNCTION="chk_proc_libs" ;; fortify-file=*) CHK_FORTIFY_FILE=${OPTARG#*=} OPT=$((OPT + 1)) CHK_FUNCTION="chk_fortify_file" ;; fortify-proc=*) CHK_FORTIFY_PROC=${OPTARG#*=} OPT=$((OPT + 1)) CHK_FUNCTION="chk_fortify_proc" ;; kernel=*) CHK_KERNEL=${OPTARG#*=} OPT=$((OPT + 1)) CHK_FUNCTION="chk_kernel" ;; kernel) OPT=$((OPT + 1)) CHK_FUNCTION="chk_kernel" ;; *) printf "\033[31mError: Unknown option %s.\033[m\n\n" "${OPTARG}" exit 1 ;; esac ;; *) help exit 0 ;; esac done if [[ "${OPT}" == 0 ]]; then printf "\033[31mError: No option selected. Please select an option.\033[m\n\n" exit 1 elif [[ "${OPT}" != 1 ]]; then printf "\033[31mError: To many options selected. Please select one at a time.\033[m\n\n" exit 1 fi for variable in CHK_DIR CHK_FILE CHK_FORTIFY_FILE CHK_FORTIFY_PROC CHK_PROC CHK_PROC_LIBS; do if [[ -n ${!variable+x} ]]; then if [[ -z "${!variable}" ]]; then printf "\033[31mError: Option Required.\033[m\n\n" help exit 1 fi fi done # call the function ${CHK_FUNCTION}