diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index f4fc29b..a47457b 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -20,5 +20,3 @@ jobs: fi - name: ubuntu checksec run: docker-compose run checksec-ubuntu - - name: photon checksec - run: docker-compose run checksec-photon diff --git a/Dockerfile.photon b/Dockerfile.photon deleted file mode 100644 index b81c44a..0000000 --- a/Dockerfile.photon +++ /dev/null @@ -1,15 +0,0 @@ -FROM photon:5.0 - -# Install dependencies -RUN tdnf upgrade -y && tdnf remove toybox -y && \ - tdnf install -y build-essential git rpm-build coreutils util-linux \ - make autoconf automake gcc ncurses-devel sed tar texinfo wget procps-ng grep \ - findutils gzip file which libxml2 python3 python3-pip jq clang nasm binutils && \ - pip3 install --upgrade pip && pip3 install setuptools && \ - pip3 install demjson3 && mkdir -p /zig && \ - wget https://ziglang.org/builds/zig-linux-$(uname -m)-0.12.0-dev.3667+77abd3a96.tar.xz && \ - tar xf zig-linux-$(uname -m)-0.12.0-dev.3667+77abd3a96.tar.xz -C /zig --strip-components=1 && \ - rm -rf zig-linux-$(uname -m)-0.12.0-dev.3667+77abd3a96.tar.xz - -COPY . /root -WORKDIR /root diff --git a/Dockerfile.ubuntu b/Dockerfile.ubuntu index ac5c049..c73f142 100644 --- a/Dockerfile.ubuntu +++ b/Dockerfile.ubuntu @@ -1,16 +1,9 @@ FROM ubuntu:22.04 -# Install dependencies -RUN apt-get update && apt-get -y -q upgrade && DEBIAN_FRONTEND=noninteractive apt-get -y -q install \ - bc bison flex build-essential git file \ - libncurses-dev libssl-dev u-boot-tools wget \ - xz-utils vim libxml2-utils python3 python3-pip jq \ - gcc clang gcc-multilib nasm binutils && apt-get clean \ - pip3 install --upgrade pip && pip3 install setuptools && \ - pip3 install demjson3 && mkdir -p /zig && \ - wget https://ziglang.org/builds/zig-linux-$(uname -m)-0.12.0-dev.3667+77abd3a96.tar.xz && \ - tar xf zig-linux-$(uname -m)-0.12.0-dev.3667+77abd3a96.tar.xz -C /zig --strip-components=1 && \ - rm -rf zig-linux-$(uname -m)-0.12.0-dev.3667+77abd3a96.tar.xz +# install the build script and run it. +# this is to give more flexiblity to the build process +COPY tests/docker-build.sh /tmp +RUN /tmp/docker-build.sh COPY . /root WORKDIR /root diff --git a/checksec b/checksec index b6f5dc3..d6e5bec 100755 --- a/checksec +++ b/checksec @@ -51,6 +51,9 @@ 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" +# Currently unused, adding for reference +# https://github.com/gcc-mirror/gcc/blob/master/gcc/builtins.def#L1112 +# FORTIFY_FUNCTIONS=(memcpy_chk memmove_chk mempcpy_chk memset_chk stpcpy_chk stpncpy_chk strcat_chk strcpy_chk strncat_chk strncpy_chk snprintf_chk sprintf_chk vsnprintf_chk vsprintf_chk fprintf_chk printf_chk vfprintf_chk vprintf_chk) pkg_release=false commandsmissing=false @@ -817,7 +820,7 @@ filecheck() { # 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",' + 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 @@ -834,18 +837,12 @@ filecheck() { FS_cnt_unchecked=$(grep -cFxf <(sort -u <<< "${FS_func_libc}") <(sort -u <<< "${FS_func}")) FS_cnt_total=$((FS_cnt_unchecked + FS_cnt_checked)) - if [[ "${libc_found}" == "false" ]] || [[ "${FS_cnt_total}" == "0" ]]; then + if [[ "${libc_found}" == "false" ]] || [[ "${FS_cnt_total}" -eq "0" ]]; then echo_message "\033[32mN/A\033[m" "N/A," ' fortify_source="n/a" ' '"fortify_source":"n/a",' + elif [[ "${FS_cnt_checked}" -eq "0" ]]; then + echo_message "\033[31mNo\033[m" "No," ' fortify_source="no" ' '"fortify_source":"no",' else - if [[ $FS_cnt_checked -eq $FS_cnt_total ]]; then - echo_message '\033[32mYes\033[m' 'Yes,' ' fortify_source="yes" ' '"fortify_source":"yes",' - else - if [[ "${FS_cnt_checked}" == "0" ]]; then - echo_message "\033[31mNo\033[m" "No," ' fortify_source="no" ' '"fortify_source":"no",' - else - echo_message "\033[33mPartial\033[m" "Partial," ' fortify_source="partial" ' '"fortify_source":"partial",' - fi - fi + echo_message '\033[32mYes\033[m' 'Yes,' ' fortify_source="yes" ' '"fortify_source":"yes",' 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}\"" @@ -1621,18 +1618,12 @@ proccheck() { Proc_FS_cnt_unchecked=$(grep -cFxf <(sort -u <<< "${Proc_FS_func_libc}") <(sort -u <<< "${Proc_FS_func}")) Proc_FS_cnt_total=$((Proc_FS_cnt_unchecked + Proc_FS_cnt_checked)) - if [[ "${libc_found}" == "false" ]] || [[ "${Proc_FS_cnt_total}" == "0" ]]; then + if [[ "${libc_found}" == "false" ]] || [[ "${Proc_FS_cnt_total}" -eq "0" ]]; then echo_message "\033[32mN/A\033[m" "N/A," ' fortify_source="n/a">' '"fortify_source":"n/a" }' + elif [[ "${Proc_FS_cnt_checked}" -eq "0" ]]; then + echo_message "\033[31mNo\033[m" "No," ' fortify_source="no">' '"fortify_source":"no" }' else - if [[ $Proc_FS_cnt_checked -eq $Proc_FS_cnt_total ]]; then - echo_message '\033[32mYes\033[m' 'Yes,' ' fortify_source="yes">' '"fortify_source":"yes" }' - else - if [[ "${Proc_FS_cnt_checked}" == "0" ]]; then - echo_message "\033[31mNo\033[m" "No," ' fortify_source="no">' '"fortify_source":"no" }' - else - echo_message "\033[33mPartial\033[m" "Partial," ' fortify_source="partial">' '"fortify_source":"partial" }' - fi - fi + echo_message '\033[32mYes\033[m' 'Yes,' ' fortify_source="yes">' '"fortify_source":"yes" }' fi } diff --git a/docker-compose.yml b/docker-compose.yml index 5e0ce87..d4a8ebb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '2' - services: checksec-ubuntu: build: @@ -8,13 +6,6 @@ services: image: checksec-ubuntu command: bash -c "./tests/test-checksec.sh" - checksec-photon: - build: - context: ./ - dockerfile: Dockerfile.photon - image: checksec-photon - command: bash -c "./tests/test-checksec.sh" - shellcheck: volumes: - .:/mnt diff --git a/docs/index.md b/docs/index.md index 18b71c8..80ad4dd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -71,6 +71,15 @@ SUMMARY: * Number of unchecked functions in the executable : 6 ``` +Note on Fortify results. There is not currently a known way to determine if the binary was compiled with FORTIFY_SOURCE level 1, 2, or 3 in a reliable manner. + +Some binaries include some details about how it was compiled. For example, VIM on ubuntu is compiled with `-D_FORTIFY_SOURCE=1`. This can be identified with strings on the binary. Most binaries do not include this data, but some do. + +``` +$ strings vim | grep FORTIFY +gcc -c -I. -Iproto -DHAVE_CONFIG_H -Wdate-time -g -O2 -ffile-prefix-map=/build/vim-CSyBG7/vim-8.2.3995=. -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -D_REENTRANT -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 +``` + #### **Kernel test in Cli** ```bash $ checksec --kernel diff --git a/src/core.sh b/src/core.sh index 050f20f..3e66f20 100644 --- a/src/core.sh +++ b/src/core.sh @@ -18,6 +18,9 @@ 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" +# Currently unused, adding for reference +# https://github.com/gcc-mirror/gcc/blob/master/gcc/builtins.def#L1112 +# FORTIFY_FUNCTIONS=(memcpy_chk memmove_chk mempcpy_chk memset_chk stpcpy_chk stpncpy_chk strcat_chk strcpy_chk strncat_chk strncpy_chk snprintf_chk sprintf_chk vsnprintf_chk vsprintf_chk fprintf_chk printf_chk vfprintf_chk vprintf_chk) pkg_release=false commandsmissing=false diff --git a/src/functions/filecheck.sh b/src/functions/filecheck.sh index 465e771..6d1510a 100644 --- a/src/functions/filecheck.sh +++ b/src/functions/filecheck.sh @@ -124,7 +124,7 @@ filecheck() { # 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",' + 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 @@ -141,18 +141,12 @@ filecheck() { FS_cnt_unchecked=$(grep -cFxf <(sort -u <<< "${FS_func_libc}") <(sort -u <<< "${FS_func}")) FS_cnt_total=$((FS_cnt_unchecked + FS_cnt_checked)) - if [[ "${libc_found}" == "false" ]] || [[ "${FS_cnt_total}" == "0" ]]; then + if [[ "${libc_found}" == "false" ]] || [[ "${FS_cnt_total}" -eq "0" ]]; then echo_message "\033[32mN/A\033[m" "N/A," ' fortify_source="n/a" ' '"fortify_source":"n/a",' + elif [[ "${FS_cnt_checked}" -eq "0" ]]; then + echo_message "\033[31mNo\033[m" "No," ' fortify_source="no" ' '"fortify_source":"no",' else - if [[ $FS_cnt_checked -eq $FS_cnt_total ]]; then - echo_message '\033[32mYes\033[m' 'Yes,' ' fortify_source="yes" ' '"fortify_source":"yes",' - else - if [[ "${FS_cnt_checked}" == "0" ]]; then - echo_message "\033[31mNo\033[m" "No," ' fortify_source="no" ' '"fortify_source":"no",' - else - echo_message "\033[33mPartial\033[m" "Partial," ' fortify_source="partial" ' '"fortify_source":"partial",' - fi - fi + echo_message '\033[32mYes\033[m' 'Yes,' ' fortify_source="yes" ' '"fortify_source":"yes",' 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}\"" diff --git a/src/functions/proccheck.sh b/src/functions/proccheck.sh index b2baa02..22dd7c9 100644 --- a/src/functions/proccheck.sh +++ b/src/functions/proccheck.sh @@ -130,17 +130,11 @@ proccheck() { Proc_FS_cnt_unchecked=$(grep -cFxf <(sort -u <<< "${Proc_FS_func_libc}") <(sort -u <<< "${Proc_FS_func}")) Proc_FS_cnt_total=$((Proc_FS_cnt_unchecked + Proc_FS_cnt_checked)) - if [[ "${libc_found}" == "false" ]] || [[ "${Proc_FS_cnt_total}" == "0" ]]; then + if [[ "${libc_found}" == "false" ]] || [[ "${Proc_FS_cnt_total}" -eq "0" ]]; then echo_message "\033[32mN/A\033[m" "N/A," ' fortify_source="n/a">' '"fortify_source":"n/a" }' + elif [[ "${Proc_FS_cnt_checked}" -eq "0" ]]; then + echo_message "\033[31mNo\033[m" "No," ' fortify_source="no">' '"fortify_source":"no" }' else - if [[ $Proc_FS_cnt_checked -eq $Proc_FS_cnt_total ]]; then - echo_message '\033[32mYes\033[m' 'Yes,' ' fortify_source="yes">' '"fortify_source":"yes" }' - else - if [[ "${Proc_FS_cnt_checked}" == "0" ]]; then - echo_message "\033[31mNo\033[m" "No," ' fortify_source="no">' '"fortify_source":"no" }' - else - echo_message "\033[33mPartial\033[m" "Partial," ' fortify_source="partial">' '"fortify_source":"partial" }' - fi - fi + echo_message '\033[32mYes\033[m' 'Yes,' ' fortify_source="yes">' '"fortify_source":"yes" }' fi } diff --git a/tests/docker-build.sh b/tests/docker-build.sh new file mode 100755 index 0000000..11cdfcd --- /dev/null +++ b/tests/docker-build.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# build the container with a shell script so that it is bash +# Dockerfile syntax is sh not bash so installing gcc-multilib in an +# if condition becomes more difficult. + +set -eou pipefail + +apt-get update +apt-get -y -q upgrade + +DEBIAN_FRONTEND=noninteractive apt-get -y -q install \ + bc bison flex build-essential git file \ + libncurses-dev libssl-dev u-boot-tools wget \ + xz-utils vim libxml2-utils python3 python3-pip jq \ + gcc clang nasm binutils + +if [[ "$(uname -m)" == "x86_64" ]]; then + apt-get -y -q install gcc-multilib +fi + +apt-get clean + +pip3 install --upgrade pip +pip3 install setuptools demjson3 diff --git a/tests/hardening-checks.sh b/tests/hardening-checks.sh index 62c9e0e..164c00e 100755 --- a/tests/hardening-checks.sh +++ b/tests/hardening-checks.sh @@ -276,13 +276,6 @@ for bin in nolibc nolibc_cl nolibc32 nolibc_cl32 fszero fszero_cl fszero32 fszer exit 1 fi done -# Partial -for bin in partial partial32 partial_cl partial_cl32; do - if [[ $("${PARENT}"/checksec --file="${DIR}/binaries/output/${bin}" --format=csv | cut -d, -f8) != "Partial" ]]; then - echo "No Fortify validation failed on \"${bin}\": $("${PARENT}"/checksec --file="${DIR}/binaries/${bin}" --format=csv | cut -d, -f8)" - exit 1 - fi -done echo "Fortify validation tests passed" #============================================ @@ -453,14 +446,6 @@ for bin in nolibc nolibc_cl nolibc32 nolibc_cl32 fszero fszero_cl fszero32 fszer exit 1 fi done -# Partial -for bin in partial partial32 partial_cl partial_cl32; do - "${DIR}"/binaries/output/${bin} > /dev/null & - if [[ $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f8) != "Partial" ]]; then - echo "No Fortify process validation failed on \"${bin}\": $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f8)" - 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 1d89d4e..1559b0a 100755 --- a/tests/test-checksec.sh +++ b/tests/test-checksec.sh @@ -7,7 +7,4 @@ 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 +"${DIR}"/hardening-checks.sh || exit 2