diff --git a/Dockerfile.photon b/Dockerfile.photon index 3e0557d..5bbc218 100644 --- a/Dockerfile.photon +++ b/Dockerfile.photon @@ -6,7 +6,7 @@ RUN tdnf upgrade -y && tdnf remove toybox -y && \ make autoconf automake gcc ncurses-devel sed tar texinfo procps-ng grep \ findutils gzip file which libxml2 python3 python3-pip jq && \ pip3 install --upgrade pip && pip3 install setuptools && \ - pip3 install demjson + pip3 install demjson3 COPY . /root WORKDIR /root diff --git a/Dockerfile.ubuntu b/Dockerfile.ubuntu index a36c199..9a95274 100644 --- a/Dockerfile.ubuntu +++ b/Dockerfile.ubuntu @@ -5,6 +5,7 @@ RUN apt-get update && apt-get -y -q upgrade && DEBIAN_FRONTEND=noninteractive ap bc bison flex build-essential ccache git \ libncurses-dev libssl-dev u-boot-tools wget \ xz-utils vim xfce4 libxml2-utils python-demjson jq \ + gcc-multilib clang \ && apt-get clean COPY . /root diff --git a/checksec b/checksec index 4ab4fc1..7cbe06b 100755 --- a/checksec +++ b/checksec @@ -86,7 +86,7 @@ command_exists() { type "${1}" > /dev/null 2>&1 } -for command in cat awk sed sysctl objdump uname mktemp openssl grep stat file find sort head ps readlink basename id which xargs ldd; do +for command in cat awk sed sysctl objdump uname mktemp openssl grep stat file find sort head ps readlink basename id which xargs ldd tr; do if ! (command_exists ${command}); then echo >&2 -e "\e[31mWARNING: '${command}' not found! It's required for most checks.\e[0m" commandsmissing=true @@ -501,19 +501,18 @@ chk_proc() { 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 - + # assume a process name was given + IFS=" " read -r -a fpids <<< "$(pgrep -d ' ' "${CHK_PROC}")" + # if nothing was found check if it is a PID if [[ ${#fpids} -eq 0 ]]; then - printf "\033[31mError: No process with the given name or pid found.\033[m\n\n" - exit 1 + if (isNumeric "${CHK_PROC}") && [[ -n "$(ps -p "${CHK_PROC}" -o pid=)" ]]; then + fpids=("${CHK_PROC}") + else + printf "\033[31mError: Please provide a valid process name or pid.\033[m\n\n" + exit 1 + fi fi + echo_message "* System-wide ASLR" '' '' '' aslrcheck echo_message "* Does the CPU support NX: " '' '' '' @@ -699,8 +698,8 @@ debug_report() { # check file(s) filecheck() { # check for RELRO support - if [[ $(${readelf} -l "${1}") =~ "no program headers" ]]; then - echo_message '\033[31mN/A \033[m ' 'N/A,' ' /dev/null) =~ "no program headers" ]]; then + echo_message '\033[32mN/A \033[m ' 'N/A,' ' /dev/null | grep -q 'GNU_RELRO'; then if ${readelf} -d "${1}" 2> /dev/null | grep -q 'BIND_NOW' || ! ${readelf} -l "${1}" 2> /dev/null | grep -q '\.got\.plt'; then echo_message '\033[32mFull RELRO \033[m ' 'Full RELRO,' ' /dev/null) =~ "no program headers" ]]; then + echo_message '\033[32mN/A \033[m ' 'N/A,' ' nx="n/a"' '"nx":"n/a",' elif ${readelf} -l "${1}" 2> /dev/null | grep -q 'GNU_STACK'; then - if [[ $(${s_readelf} -l "${1}" 2> /dev/null | grep -A 1 'GNU_STACK' | sed 'N;s/\n//g' | grep -Eo "0x[0-9a-f]{16}" | grep -v 0x0000000000000000 | wc -l) -gt 0 ]]; then + if [[ $(${readelf} -l "${1}" 2> /dev/null | grep 'GNU_STACK' | grep -oP '(?<=0x).*(?=RW )' | grep -o . | sort -u | tr -d '\n') != " 0x" ]]; 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",' @@ -778,7 +777,7 @@ filecheck() { # 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]" - if [[ $(${readelf} -d "${1}") =~ "no dynamic section" ]]; then + if [[ $(${readelf} -d "${1}" 2> /dev/null) =~ "no dynamic section" ]]; then echo_message '\033[32mN/A \033[m ' 'N/A,' ' rpath="n/a"' '"rpath":"n/a",' else IFS=: read -r -a rpath_array <<< "$(${readelf} -d "${1}" 2> /dev/null | awk -F'[][]' '/RPATH/ {print $2}')" @@ -794,7 +793,7 @@ filecheck() { fi # search for a line that matches RUNPATH and extract the colon-separated path list within brackets - if [[ $(${readelf} -d "${1}") =~ "no dynamic section" ]]; then + if [[ $(${readelf} -d "${1}" 2> /dev/null) =~ "no dynamic section" ]]; then echo_message '\033[32mN/A \033[m ' 'N/A,' ' runpath="n/a"' '"runpath":"n/a",' else IFS=: read -r -a runpath_array <<< "$(${readelf} -d "${1}" 2> /dev/null | awk -F'[][]' '/RUNPATH/ {print $2}')" @@ -949,11 +948,6 @@ 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]" @@ -1502,8 +1496,8 @@ proccheck() { fi # check for stack canary support - if ${readelf} -W -s "${1}/exe" 2> /dev/null | grep -q 'Symbol table'; then - if ${readelf} -W -s "${1}/exe" 2> /dev/null | grep " UND " | grep -Eq '__stack_chk_fail|__stack_chk_guard|__intel_security_cookie'; then + if ${readelf} -s "${1}/exe" 2> /dev/null | grep -q 'Symbol table'; then + if ${readelf} -s "${1}/exe" 2> /dev/null | grep " UND " | 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",' @@ -1570,10 +1564,10 @@ proccheck() { echo_message '\033[31mPaX disabled\033[m ' 'Pax disabled,' ' pax="no"' '"pax":"no",' fi # fallback check for NX support - elif [[ $(${s_readelf} -l "${1}/exe" 2> /dev/null | grep -A 1 'GNU_STACK' | sed 'N;s/\n//g' | grep -Eo "0x[0-9a-f]{16}" | grep -v 0x0000000000000000 | wc -l) -gt 0 ]]; then + elif [[ $(${readelf} -l "${1}/exe" 2> /dev/null | grep 'GNU_STACK' | grep -oP '(?<=0x).*(?=RW )' | grep -o . | sort -u | tr -d '\n') != " 0x" ]]; 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",' + echo_message '\033[32mNX enabled \033[m ' 'NX enabled,' ' nx="yes"' '"nx":"yes",' fi # check for PIE support @@ -1651,7 +1645,6 @@ upgrade() { rm -f "${TMP_FILE}" "${SIG_FILE}" "${PUBKEY_FILE}" > /dev/null 2>&1 exit 1 fi - exit 0 } # Version compare diff --git a/src/core.sh b/src/core.sh index ada5a5f..2431838 100644 --- a/src/core.sh +++ b/src/core.sh @@ -53,7 +53,7 @@ command_exists() { type "${1}" > /dev/null 2>&1 } -for command in cat awk sed sysctl objdump uname mktemp openssl grep stat file find sort head ps readlink basename id which xargs ldd; do +for command in cat awk sed sysctl objdump uname mktemp openssl grep stat file find sort head ps readlink basename id which xargs ldd tr; do if ! (command_exists ${command}); then echo >&2 -e "\e[31mWARNING: '${command}' not found! It's required for most checks.\e[0m" commandsmissing=true diff --git a/src/functions/chk_proc.sh b/src/functions/chk_proc.sh index a1bee80..6ec8e6c 100644 --- a/src/functions/chk_proc.sh +++ b/src/functions/chk_proc.sh @@ -59,19 +59,18 @@ chk_proc() { 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 - + # assume a process name was given + IFS=" " read -r -a fpids <<< "$(pgrep -d ' ' "${CHK_PROC}")" + # if nothing was found check if it is a PID if [[ ${#fpids} -eq 0 ]]; then - printf "\033[31mError: No process with the given name or pid found.\033[m\n\n" - exit 1 + if (isNumeric "${CHK_PROC}") && [[ -n "$(ps -p "${CHK_PROC}" -o pid=)" ]]; then + fpids=("${CHK_PROC}") + else + printf "\033[31mError: Please provide a valid process name or pid.\033[m\n\n" + exit 1 + fi fi + echo_message "* System-wide ASLR" '' '' '' aslrcheck echo_message "* Does the CPU support NX: " '' '' '' diff --git a/src/functions/filecheck.sh b/src/functions/filecheck.sh index 64b992d..ac70593 100644 --- a/src/functions/filecheck.sh +++ b/src/functions/filecheck.sh @@ -5,8 +5,8 @@ # check file(s) filecheck() { # check for RELRO support - if [[ $(${readelf} -l "${1}") =~ "no program headers" ]]; then - echo_message '\033[31mN/A \033[m ' 'N/A,' ' /dev/null) =~ "no program headers" ]]; then + echo_message '\033[32mN/A \033[m ' 'N/A,' ' /dev/null | grep -q 'GNU_RELRO'; then if ${readelf} -d "${1}" 2> /dev/null | grep -q 'BIND_NOW' || ! ${readelf} -l "${1}" 2> /dev/null | grep -q '\.got\.plt'; then echo_message '\033[32mFull RELRO \033[m ' 'Full RELRO,' ' /dev/null) =~ "no program headers" ]]; then + echo_message '\033[32mN/A \033[m ' 'N/A,' ' nx="n/a"' '"nx":"n/a",' elif ${readelf} -l "${1}" 2> /dev/null | grep -q 'GNU_STACK'; then - if [[ $(${s_readelf} -l "${1}" 2> /dev/null | grep -A 1 'GNU_STACK' | sed 'N;s/\n//g' | grep -Eo "0x[0-9a-f]{16}" | grep -v 0x0000000000000000 | wc -l) -gt 0 ]]; then + if [[ $(${readelf} -l "${1}" 2> /dev/null | grep 'GNU_STACK' | grep -oP '(?<=0x).*(?=RW )' | grep -o . | sort -u | tr -d '\n') != " 0x" ]]; 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",' @@ -84,7 +84,7 @@ filecheck() { # 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]" - if [[ $(${readelf} -d "${1}") =~ "no dynamic section" ]]; then + if [[ $(${readelf} -d "${1}" 2> /dev/null) =~ "no dynamic section" ]]; then echo_message '\033[32mN/A \033[m ' 'N/A,' ' rpath="n/a"' '"rpath":"n/a",' else IFS=: read -r -a rpath_array <<< "$(${readelf} -d "${1}" 2> /dev/null | awk -F'[][]' '/RPATH/ {print $2}')" @@ -100,7 +100,7 @@ filecheck() { fi # search for a line that matches RUNPATH and extract the colon-separated path list within brackets - if [[ $(${readelf} -d "${1}") =~ "no dynamic section" ]]; then + if [[ $(${readelf} -d "${1}" 2> /dev/null) =~ "no dynamic section" ]]; then echo_message '\033[32mN/A \033[m ' 'N/A,' ' runpath="n/a"' '"runpath":"n/a",' else IFS=: read -r -a runpath_array <<< "$(${readelf} -d "${1}" 2> /dev/null | awk -F'[][]' '/RUNPATH/ {print $2}')" diff --git a/src/functions/general_functions.sh b/src/functions/general_functions.sh index 5608615..3be45b5 100644 --- a/src/functions/general_functions.sh +++ b/src/functions/general_functions.sh @@ -18,8 +18,3 @@ echo_message() { isNumeric() { echo "$@" | grep -q -v "[^0-9]" } - -# check if input is a string -isString() { - echo "$@" | grep -q -v "[^ A-Z_a-z]" -} diff --git a/src/functions/proccheck.sh b/src/functions/proccheck.sh index d8b976a..5ac5070 100644 --- a/src/functions/proccheck.sh +++ b/src/functions/proccheck.sh @@ -21,8 +21,8 @@ proccheck() { fi # check for stack canary support - if ${readelf} -W -s "${1}/exe" 2> /dev/null | grep -q 'Symbol table'; then - if ${readelf} -W -s "${1}/exe" 2> /dev/null | grep " UND " | grep -Eq '__stack_chk_fail|__stack_chk_guard|__intel_security_cookie'; then + if ${readelf} -s "${1}/exe" 2> /dev/null | grep -q 'Symbol table'; then + if ${readelf} -s "${1}/exe" 2> /dev/null | grep " UND " | 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",' @@ -89,10 +89,10 @@ proccheck() { echo_message '\033[31mPaX disabled\033[m ' 'Pax disabled,' ' pax="no"' '"pax":"no",' fi # fallback check for NX support - elif [[ $(${s_readelf} -l "${1}/exe" 2> /dev/null | grep -A 1 'GNU_STACK' | sed 'N;s/\n//g' | grep -Eo "0x[0-9a-f]{16}" | grep -v 0x0000000000000000 | wc -l) -gt 0 ]]; then + elif [[ $(${readelf} -l "${1}/exe" 2> /dev/null | grep 'GNU_STACK' | grep -oP '(?<=0x).*(?=RW )' | grep -o . | sort -u | tr -d '\n') != " 0x" ]]; 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",' + echo_message '\033[32mNX enabled \033[m ' 'NX enabled,' ' nx="yes"' '"nx":"yes",' fi # check for PIE support diff --git a/src/functions/upgrade.sh b/src/functions/upgrade.sh index 3827df1..4be7665 100644 --- a/src/functions/upgrade.sh +++ b/src/functions/upgrade.sh @@ -46,7 +46,6 @@ upgrade() { rm -f "${TMP_FILE}" "${SIG_FILE}" "${PUBKEY_FILE}" > /dev/null 2>&1 exit 1 fi - exit 0 } # Version compare diff --git a/tests/binaries/build_binaries.sh b/tests/binaries/build_binaries.sh new file mode 100755 index 0000000..33c6059 --- /dev/null +++ b/tests/binaries/build_binaries.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# All hardening features on (except for CFI and SafeStack) +gcc -o all test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z now -z noexecstack -pie -s +# Partial RELRO +gcc -o partial test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z lazy -z noexecstack -s +# RPATH +gcc -o rpath test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z now -z noexecstack -pie -s -Wl,-rpath,./ -Wl,--disable-new-dtags +# RUNPATH +gcc -o runpath test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z now -z noexecstack -pie -s -Wl,-rpath,./ -Wl,--enable-new-dtags +# no hardening features +gcc -o none test.c -w -D_FORTIFY_SOURCE=0 -fno-stack-protector -no-pie -O2 -z norelro -z lazy -z execstack +# REL (PIE) +gcc -c test.c -o rel.o +# DSO (PIE) +gcc -shared -fPIC -o dso.so test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -O2 -z relro -z now -z noexecstack -s +# CFI and SafeStack +clang -o cfi test.c -w -flto -fsanitize=cfi -fvisibility=default +clang -o sstack test.c -w -fsanitize=safe-stack +# clang instead of gcc +clang -o all_cl test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z now -z noexecstack -pie -s +clang -o partial_cl test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z lazy -z noexecstack -s +clang -o rpath_cl test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z now -z noexecstack -pie -s -Wl,-rpath,./ -Wl,--disable-new-dtags +clang -o runpath_cl test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z now -z noexecstack -pie -s -Wl,-rpath,./ -Wl,--enable-new-dtags +clang -o none_cl test.c -w -D_FORTIFY_SOURCE=0 -fno-stack-protector -no-pie -O2 -z norelro -z lazy -z execstack +clang -c test.c -o rel_cl.o +clang -shared -fPIC -o dso_cl.so test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -O2 -z relro -z now -z noexecstack -s + +# 32-bit (you might need 'sudo apt install gcc-multilib') +gcc -m32 -o all32 test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z now -z noexecstack -pie -s +gcc -m32 -o partial32 test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z lazy -z noexecstack -s +gcc -m32 -o rpath32 test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z now -z noexecstack -pie -s -Wl,-rpath,./ -Wl,--disable-new-dtags +gcc -m32 -o runpath32 test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z now -z noexecstack -pie -s -Wl,-rpath,./ -Wl,--enable-new-dtags +gcc -m32 -o none32 test.c -w -D_FORTIFY_SOURCE=0 -fno-stack-protector -no-pie -O2 -z norelro -z lazy -z execstack +gcc -m32 -c test.c -o rel32.o +gcc -m32 -shared -fPIC -o dso32.so test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -O2 -z relro -z now -z noexecstack -s +clang -m32 -o cfi32 test.c -w -flto -fsanitize=cfi -fvisibility=default +clang -m32 -o sstack32 test.c -w -fsanitize=safe-stack +clang -m32 -o all_cl32 test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z now -z noexecstack -pie -s +clang -m32 -o partial_cl32 test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z lazy -z noexecstack -s +clang -m32 -o rpath_cl32 test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z now -z noexecstack -pie -s -Wl,-rpath,./ -Wl,--disable-new-dtags +clang -m32 -o runpath_cl32 test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -O2 -z relro -z now -z noexecstack -pie -s -Wl,-rpath,./ -Wl,--enable-new-dtags +clang -m32 -o none_cl32 test.c -w -D_FORTIFY_SOURCE=0 -fno-stack-protector -no-pie -O2 -z norelro -z lazy -z execstack +clang -m32 -c test.c -o rel_cl32.o +clang -m32 -shared -fPIC -o dso_cl32.so test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -O2 -z relro -z now -z noexecstack -s diff --git a/tests/binaries/test.c b/tests/binaries/test.c new file mode 100644 index 0000000..c072f58 --- /dev/null +++ b/tests/binaries/test.c @@ -0,0 +1,20 @@ +#include +#include +#include + +int false__stack_chk_fail(int a) { return a; } + +int main(int argc, char** argv) { + char buf[16]; + int (*op)(int) = false__stack_chk_fail; + + if (argc>1) + strcpy(buf,argv[1]); + else + strcpy(buf,"test"); + + printf("%s,%d\n", buf, op(42)); + + sleep(2); + return 0; +} diff --git a/tests/hardening-checks.sh b/tests/hardening-checks.sh new file mode 100755 index 0000000..ba3f252 --- /dev/null +++ b/tests/hardening-checks.sh @@ -0,0 +1,434 @@ +#!/usr/bin/env bash + +DIR=$( + cd "$(dirname "$0")" + pwd +) +PARENT=$( + cd "$(dirname "$0")/.." + pwd +) + +( + cd "${DIR}/binaries/" + ./build_binaries.sh +) + +for bin in all all32 all_cl all_cl32 \ + cfi cfi32 sstack sstack32 \ + dso.so dso32.so dso_cl.so dso_cl32.so \ + none none32 none_cl none_cl32 \ + partial partial32 partial_cl partial_cl32 \ + rel.o rel32.o rel_cl.o rel_cl32.o \ + rpath rpath32 rpath_cl rpath_cl32 \ + runpath runpath32 runpath_cl runpath_cl32; do + if [[ ! -f "${DIR}/binaries/${bin}" ]]; then + echo "Could not find test file \"${bin}\". Run build_binaries.sh in the binaries folder to generate it." + exit 255 + fi +done + +#============================================ +# file checks +#============================================ + +echo "Starting RELRO check" +# Full RELRO +for bin in all all32 all_cl all_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f1) != "Full RELRO" ]]; then + echo "Full RELRO validation failed on \"${bin}\"" + exit 1 + fi +done +# Partial RELRO +for bin in partial partial32 partial_cl partial_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f1) != "Partial RELRO" ]]; then + echo "Partial RELRO validation failed on \"${bin}\"" + exit 1 + fi +done +# No RELRO +for bin in none none32 none_cl none_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f1) != "No RELRO" ]]; then + echo "No RELRO validation failed on \"${bin}\"" + exit 1 + fi +done +# N/A +for bin in rel.o rel32.o rel_cl.o rel_cl32.o; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f1) != "N/A" ]]; then + echo "N/A RELRO validation failed on \"${bin}\"" + exit 1 + fi +done +echo "RELRO validation tests passed" + +#============================================ + +echo "Starting Stack Canary check" +# Canary found +for bin in all all32 all_cl all_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f2) != "Canary found" ]]; then + echo "Stack Canary validation failed on \"${bin}\"" + exit 1 + fi +done +# No Canary found +for bin in none none32 none_cl none_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f2) != "No Canary found" ]]; then + echo "No Stack Canary validation failed on \"${bin}\"" + exit 1 + fi +done +echo "Stack Canary validation tests passed" + +#============================================ + +echo "Starting NX check" +# NX enabled +for bin in all all32 all_cl all_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f3) != "NX enabled" ]]; then + echo "NX enabled validation failed on \"${bin}\"" + exit 1 + fi +done +# NX disabled +for bin in none none32 none_cl none_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f3) != "NX disabled" ]]; then + echo "NX disabled validation failed on \"${bin}\"" + exit 1 + fi +done +# N/A +for bin in rel.o rel32.o rel_cl.o rel_cl32.o; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f3) != "N/A" ]]; then + echo "N/A NX validation failed on \"${bin}\"" + exit 1 + fi +done +echo "NX validation tests passed" + +#============================================ + +echo "Starting PIE check" +# PIE enabled +for bin in all all32 all_cl all_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f4) != "PIE enabled" ]]; then + echo "PIE enabled validation failed on \"${bin}\"" + exit 1 + fi +done +# No PIE +for bin in none none32 none_cl none_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f4) != "No PIE" ]]; then + echo "No PIE validation failed on \"${bin}\"" + exit 1 + fi +done +# DSO +for bin in dso.so dso32.so dso_cl.so dso_cl32.so; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f4) != "DSO" ]]; then + echo "PIE DSO validation failed on \"${bin}\"" + exit 1 + fi +done +# REL +for bin in rel.o rel32.o rel_cl.o rel_cl32.o; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f4) != "REL" ]]; then + echo "PIE REL validation failed on \"${bin}\"" + exit 1 + fi +done +echo "PIE validation tests passed" + +#============================================ + +echo "Starting CFI check" +# with CFI +for bin in cfi cfi32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --extended --format=csv | cut -d, -f5) != "with CFI" ]]; then + echo "CFI validation failed on \"${bin}\"" + exit 1 + fi +done +# without CFI +for bin in none_cl none_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --extended --format=csv | cut -d, -f5) != "without CFI" ]]; then + echo "No CFI validation failed on \"${bin}\"" + exit 1 + fi +done +echo "CFI validation tests passed" + +#============================================ + +echo "Starting SafeStack check" +# with SafeStack +for bin in sstack sstack32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --extended --format=csv | cut -d, -f6) != "with SafeStack" ]]; then + echo "SafeStack validation failed on \"${bin}\"" + exit 1 + fi +done +# without SafeStack +for bin in none_cl none_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --extended --format=csv | cut -d, -f6) != "without SafeStack" ]]; then + echo "No SafeStack validation failed on \"${bin}\"" + exit 1 + fi +done +echo "SafeStack validation tests passed" + +#============================================ + +echo "Starting RUNPATH check" +# No RPATH +for bin in all all32 all_cl all_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f5) != "No RPATH" ]]; then + echo "No RPATH validation failed on \"${bin}\"" + exit 1 + fi +done +# RPATH +for bin in rpath rpath32 rpath_cl rpath_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f5) != "RPATH" ]]; then + echo "RPATH validation failed on \"${bin}\"" + exit 1 + fi +done +# N/A +for bin in rel.o rel32.o rel_cl.o rel_cl32.o; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f5) != "N/A" ]]; then + echo "N/A RPATH validation failed on \"${bin}\"" + exit 1 + fi +done +echo "RPATH validation tests passed" + +#============================================ + +echo "Starting RUNPATH check" +# No RUNPATH +for bin in all all32 all_cl all_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f6) != "No RUNPATH" ]]; then + echo "No RUNPATH validation failed on \"${bin}\"" + exit 1 + fi +done +# RUNPATH +for bin in runpath runpath32 runpath_cl runpath_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f6) != "RUNPATH" ]]; then + echo "RUNPATH validation failed on \"${bin}\"" + exit 1 + fi +done +# N/A +for bin in rel.o rel32.o rel_cl.o rel_cl32.o; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f6) != "N/A" ]]; then + echo "N/A RUNPATH validation failed on \"${bin}\"" + exit 1 + fi +done +echo "RUNPATH validation tests passed" + +#============================================ + +echo "Starting Symbols check" +# No Symbols +for bin in all all32 all_cl all_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f7) != "No Symbols" ]]; then + echo "No Symbols validation failed on \"${bin}\"" + exit 1 + fi +done +# Symbols +for bin in none none32 none_cl none_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f7) != "Symbols" ]]; then + echo "Symbols validation failed on \"${bin}\"" + exit 1 + fi +done +echo "Symbols validation tests passed" + +#============================================ + +echo "Starting Foritfy check" +# Yes +for bin in all all32 all_cl all_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f8) != "Yes" ]]; then + echo "Fortify validation failed on \"${bin}\"" + exit 1 + fi +done +# No +for bin in none none32 none_cl none_cl32; do + if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f8) != "No" ]]; then + echo "No Fortify validation failed on \"${bin}\"" + exit 1 + fi +done +echo "Fortify validation tests passed" + +#============================================ +# process checks +#============================================ + +echo "Starting RELRO process check" +# Full RELRO +for bin in all all32 all_cl all_cl32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f3) != "Full RELRO" ]]; then + echo "Full RELRO process validation failed on \"${bin}\"" + exit 1 + fi +done +# Partial RELRO +for bin in partial partial32 partial_cl partial_cl32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f3) != "Partial RELRO" ]]; then + echo "Partial RELRO process validation failed on \"${bin}\"" + exit 1 + fi +done +# No RELRO +for bin in none none32 none_cl none_cl32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f3) != "No RELRO" ]]; then + echo "No RELRO process validation failed on \"${bin}\"" + exit 1 + fi +done +sleep 2 +echo "RELRO process validation tests passed" + +#============================================ + +echo "Starting Stack Canary process check" +# Canary found +for bin in all all32 all_cl all_cl32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f4) != "Canary found" ]]; then + echo "Stack Canary process validation failed on \"${bin}\"" + exit 1 + fi +done +# No Canary found +for bin in none none32 none_cl none_cl32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f4) != "No Canary found" ]]; then + echo "No Stack Canary process validation failed on \"${bin}\"" + exit 1 + fi +done +sleep 2 +echo "Stack Canary process validation tests passed" + +#============================================ + +echo "Starting CFI process check" +# with CFI +for bin in cfi cfi32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --extended --format=csv | cut -d, -f5) != "with CFI" ]]; then + echo "CFI process validation failed on \"${bin}\"" + exit 1 + fi +done +# without CFI +for bin in none_cl none_cl32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --extended --format=csv | cut -d, -f5) != "without CFI" ]]; then + echo "No CFI process validation failed on \"${bin}\"" + exit 1 + fi +done +sleep 2 +echo "CFI process validation tests passed" + +#============================================ + +echo "Starting SafeStack process check" +# with SafeStack (omit 32-bit SafeStack because the binary does not work) +bin=sstack +"${DIR}"/binaries/${bin} > /dev/null & +if [[ $("${PARENT}"/checksec --proc=${bin} --extended --format=csv | cut -d, -f6) != "with SafeStack" ]]; then + echo "SafeStack process validation failed on \"${bin}\"" + exit 1 +fi +# without SafeStack +for bin in none_cl none_cl32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --extended --format=csv | cut -d, -f6) != "without SafeStack" ]]; then + echo "No SafeStack process validation failed on \"${bin}\"" + exit 1 + fi +done +sleep 2 +echo "SafeStack process validation tests passed" + +#============================================ + +echo "Starting NX process check" +# NX enabled +for bin in all all32 all_cl all_cl32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f6) != "NX enabled" ]]; then + echo "NX enabled process validation failed on \"${bin}\"" + exit 1 + fi +done +# NX disabled +for bin in none none32 none_cl none_cl32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f6) != "NX disabled" ]]; then + echo "NX disabled process validation failed on \"${bin}\"" + exit 1 + fi +done +sleep 2 +echo "NX process validation tests passed" + +#============================================ + +echo "Starting PIE process check" +# PIE enabled +for bin in all all32 all_cl all_cl32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f7) != "PIE enabled" ]]; then + echo "PIE enabled process validation failed on \"${bin}\"" + exit 1 + fi +done +# No PIE +for bin in none none32 none_cl none_cl32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f7) != "No PIE" ]]; then + echo "No PIE process validation failed on \"${bin}\"" + exit 1 + fi +done +sleep 2 +echo "PIE process validation tests passed" + +#============================================ + +echo "Starting Foritfy process check" +# Yes +for bin in all all32 all_cl all_cl32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f8) != "Yes" ]]; then + echo "Fortify process validation failed on \"${bin}\"" + exit 1 + fi +done +# No +for bin in none none32 none_cl none_cl32; do + "${DIR}"/binaries/${bin} > /dev/null & + if [[ $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f8) != "No" ]]; then + echo "No Fortify process validation failed on \"${bin}\"" + exit 1 + fi +done +echo "Fortify process validation tests passed" +echo "Done." +echo "All hardening validation tests passed" diff --git a/tests/test-checksec.sh b/tests/test-checksec.sh index 15d7411..1d89d4e 100755 --- a/tests/test-checksec.sh +++ b/tests/test-checksec.sh @@ -7,3 +7,7 @@ DIR=$( "${DIR}"/xml-checks.sh || exit 2 "${DIR}"/json-checks.sh || exit 2 + +if [ ! -f /etc/photon-release ]; then + "${DIR}"/hardening-checks.sh || exit 2 +fi