Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

checksec FORTIFY detection (proccheck) again #244

Closed
wants to merge 10 commits into from
27 changes: 23 additions & 4 deletions checksec
Original file line number Diff line number Diff line change
Expand Up @@ -1609,11 +1609,30 @@ proccheck() {
fi

#check for Fortify 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" }'
search_libc
libc_found="false"
if ${readelf} -d "$(readlink "${1}"/exe)" 2> /dev/null | grep 'NEEDED' | grep -q 'libc\.so'; then
libc_found="true"
fi
Proc_FS_filechk_func_libc="$(${readelf} -s "${use_dynamic}" "${FS_libc}" 2> /dev/null | sed -ne 's/.*__\(.*_chk\)@@.*/\1/p')"
Proc_FS_func_libc="${Proc_FS_filechk_func_libc//_chk/}"
Proc_FS_func="$(${readelf} -s "${use_dynamic}" "${1}/exe" 2> /dev/null | awk '{ print $8 }' | sed -e 's/_*//' -e 's/@.*//' -e '/^$/d')"
Proc_FS_cnt_checked=$(grep -cFxf <(sort -u <<< "${Proc_FS_filechk_func_libc}") <(sort -u <<< "${Proc_FS_func}"))
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
echo_message "\033[32mN/A\033[m" "N/A," ' fortify_source="n/a">' '"fortify_source":"n/a" }'
else
echo_message "\033[31mNo\033[m" "No" " fortify_source='no'>" '"fortify_source":"no" }'
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
fi
}

Expand Down
27 changes: 23 additions & 4 deletions src/functions/proccheck.sh
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,29 @@ proccheck() {
fi

#check for Fortify 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" }'
search_libc
libc_found="false"
if ${readelf} -d "$(readlink "${1}"/exe)" 2> /dev/null | grep 'NEEDED' | grep -q 'libc\.so'; then
libc_found="true"
fi
Proc_FS_filechk_func_libc="$(${readelf} -s "${use_dynamic}" "${FS_libc}" 2> /dev/null | sed -ne 's/.*__\(.*_chk\)@@.*/\1/p')"
Proc_FS_func_libc="${Proc_FS_filechk_func_libc//_chk/}"
Proc_FS_func="$(${readelf} -s "${use_dynamic}" "${1}/exe" 2> /dev/null | awk '{ print $8 }' | sed -e 's/_*//' -e 's/@.*//' -e '/^$/d')"
Proc_FS_cnt_checked=$(grep -cFxf <(sort -u <<< "${Proc_FS_filechk_func_libc}") <(sort -u <<< "${Proc_FS_func}"))
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
echo_message "\033[32mN/A\033[m" "N/A," ' fortify_source="n/a">' '"fortify_source":"n/a" }'
else
echo_message "\033[31mNo\033[m" "No" " fortify_source='no'>" '"fortify_source":"no" }'
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
fi
}
19 changes: 11 additions & 8 deletions tests/binaries/build_binaries.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,15 @@ clang -m32 -o output/none_cl32 test.c -w -D_FORTIFY_SOURCE=0 -fno-stack-protecto
clang -m32 -c test.c -o output/rel_cl32.o
clang -m32 -shared -fPIC -o output/dso_cl32.so test.c -w -D_FORTIFY_SOURCE=2 -fstack-protector-strong -O2 -z relro -z now -z noexecstack -s

gcc -o output/nolibc main.c start.S hello.S -w -nostdlib -no-pie -s
clang -o output/nolibc_cl main.c start.S hello.S -w -nostdlib -no-pie -s
gcc -m32 -o output/nolibc32 main.c start.S hello.S -w -nostdlib -no-pie -s
clang -m32 -o output/nolibc_cl32 main.c start.S hello.S -w -nostdlib -no-pie -s
# Fortify source (installation of NASM assembler is recommended)
nasm -f elf64 -o nolibc.o nolibc.asm
nasm -f elf32 -o nolibc32.o nolibc32.asm
gcc -o output/nolibc nolibc.o -w -nostdlib -no-pie -s
clang -o output/nolibc_cl nolibc.o -w -nostdlib -no-pie -s
gcc -m32 -o output/nolibc32 nolibc32.o -w -nostdlib -no-pie -s
clang -m32 -o output/nolibc_cl32 nolibc32.o -w -nostdlib -no-pie -s

gcc -o output/fszero helloworld.c -w -D_FORTIFY_SOURCE=0 -O2 -s
clang -o output/fszero_cl helloworld.c -w -D_FORTIFY_SOURCE=0 -O2 -s
gcc -m32 -o output/fszero32 helloworld.c -w -D_FORTIFY_SOURCE=0 -O2 -s
clang -m32 -o output/fszero_cl32 helloworld.c -w -D_FORTIFY_SOURCE=0 -O2 -s
gcc -o output/fszero fszero.c -w -D_FORTIFY_SOURCE=0 -O2 -s
clang -o output/fszero_cl fszero.c -w -D_FORTIFY_SOURCE=0 -O2 -s
gcc -m32 -o output/fszero32 fszero.c -w -D_FORTIFY_SOURCE=0 -O2 -s
clang -m32 -o output/fszero_cl32 fszero.c -w -D_FORTIFY_SOURCE=0 -O2 -s
2 changes: 2 additions & 0 deletions tests/binaries/helloworld.c → tests/binaries/fszero.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include <stdio.h>
#include <unistd.h>

int main()
{
printf("Hello World\n");
sleep(2);
return 0;
}
18 changes: 0 additions & 18 deletions tests/binaries/hello.S

This file was deleted.

7 changes: 0 additions & 7 deletions tests/binaries/main.c

This file was deleted.

23 changes: 23 additions & 0 deletions tests/binaries/nolibc.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
section .data
msg db 'Hello, World!', 0ah ;note the newline (Line Feed-LF) at the end (hex:0ah; decimal:10)
len equ $ - msg ;calculate the length of the message
delay dq 2, 100000000 ;define delay with Timespec structure members tv_sec, tv_nsec (qwords, 64-bit integer values)

section .text
global _start ;must be declared for linker (ld)

_start: ;tells linker entry point
mov rax, 1 ;system call for write (sys_write 1)
mov rdi, 1 ;file descriptor (1 is stdout)
mov rsi, msg ;address of string to output
mov rdx, len ;message length
syscall ;invoke operating system to do the write

mov rax, 35 ;system call for nanosleep (sys_nanosleep 35)
mov rdi, delay ;load the pointer to our delay
mov rsi, 0 ;exit code 0
syscall ;invoke operating system to do the delay

mov rax, 60 ;system call for exit (sys_exit 60)
xor rdi, rdi ;exit code 0
syscall ;invoke operating system to exit
Binary file added tests/binaries/nolibc.o
Binary file not shown.
23 changes: 23 additions & 0 deletions tests/binaries/nolibc32.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
section .data
msg db "Hello, world!", 0xa ;note the newline (Line Feed-LF) at the end (hex:0ah; decimal:10)
len equ $ - msg ;calculate the length of the message
delay dd 2, 100000000 ;define delay with Timespec structure members tv_sec, tv_nsec (dwords, 32-bit integer values)

section .text
global _start ;must be declared for linker (ld)

_start: ;tells linker entry point
mov eax,4 ;system call for write (sys_write 4)
mov ebx,1 ;file descriptor (1 is stdout)
mov ecx,msg ;address of string to output
mov edx,len ;message length
int 0x80 ;invoke operating system to do the write

mov eax, 162 ;system call for nanosleep (sys_nanosleep 162)
mov ebx, delay ;load the pointer to our delay
mov ecx, 0 ;exit code 0
int 0x80 ;invoke operating system to do the delay

mov eax,1 ;system call for exit (sys_exit 1)
xor ebx, ebx ;exit code 0
int 0x80 ;invoke operating system to exit
Binary file added tests/binaries/nolibc32.o
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these .o files need included? Wouldn't these be compiled by nasm?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two variants:

  1. NASM is installed together with the other packages for ubuntu checksec + photon checksec, otherwise an error occurs due to the lack of the 2 files;
  2. NASM is not installed and the two files are delivered to pass the tests.
    If the two files are delivered but NASM is also installed, the files are overwritten, as I explained in the post here and here.
    I know from experience in other open-source projects that in general binary files are not accepted in the source code but should be generated. Without installing NASM I have no way to do this, that's why I added them.
    I asked in the first post after the description for Pull requests if NASM can be installed or if I should add the object files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be added:
nasm binutils
in the docker unbuntu and photon configuration files?
https://github.com/slimm609/checksec.sh/blob/9a7f5353af5ab714abb91c1d4aecfc10ce3af8e4/Dockerfile.ubuntu#L8
gcc clang gcc-multilib nasm binutils && apt-get clean \
https://github.com/slimm609/checksec.sh/blob/9a7f5353af5ab714abb91c1d4aecfc10ce3af8e4/Dockerfile.photon#L7
findutils gzip file which libxml2 python3 python3-pip jq clang nasm binutils && \

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add nasm to the images, thats just fine. The Dockerfile.photon and Dockerfile.ubuntu are only used for testing and not shipped as part of the checksec docker image. Anything added to those 2 images is fine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will do that. If it will be OK, I will make a new Pull Requests, this is a bit messy.

Binary file not shown.
5 changes: 0 additions & 5 deletions tests/binaries/start.S

This file was deleted.

16 changes: 16 additions & 0 deletions tests/hardening-checks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,22 @@ for bin in none none32 none_cl none_cl32; do
exit 1
fi
done
# N/A
for bin in nolibc nolibc_cl nolibc32 nolibc_cl32 fszero fszero_cl fszero32 fszero_cl32; do
"${DIR}"/binaries/output/${bin} > /dev/null &
if [[ $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f8) != "N/A" ]]; then
echo "No Fortify process validation failed on \"${bin}\": $("${PARENT}"/checksec --proc=${bin} --format=csv | cut -d, -f8)"
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"
Loading