Linux binary security hardening
Recently when trying to solve a pwn challenge I used pwndbg checksec, to get to know the security properties of the executable.
With this article I want to sum up what each of the “features” imply, what and why are they used, against which attacks they protect and for the developer, which compiler options in clang and gcc cause these features to be in the binary. Even check out, what is set to be the default in these 2 compilers.
Besides checksec there is another lesser known binary, that does something similar to checksec. hardening-check which checks binaries for security hardening features. It needs to be installed with: sudo apt-get install devscript. After installation your can check any executable:
hardening-check /bin/ls
/bin/ls:
Position Independent Executable: yes
Stack protected: yes
Fortify Source functions: yes (some protected functions found)
Read-only relocations: yes
Immediate binding: no, not found!
Stack clash protection: unknown, no -fstack-clash-protection instructions found
Control flow integrity: no, not found!
If you dnt have checksec installed from pwntools you can do it by ‘python3 -m pip install — upgrade pwntools’. checksec from pwntools looks like this (and in color) :
pwn checksec — file /bin/ls
[*] ‘/bin/ls’
Arch: amd64–64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled
We notice a difference in the output. In the checkse “control flow integrity” is missing.
- ) RELRO: Will be put into a post of its own as we need to have knowledge of how dynamic linking works in ELF binaries ٩(๏_๏)۶
2.) Stack Canary:
A stack Canary is a “secret value” placed on the stack which changes every time the program is started. Before a function returns, the stack canary is checked and if it appears to be tampered with, the program exits immeadiately. Stack cookies can be leaked with the help of e.g format string vulnerabilities. They are a defense mechanism against stack buffer overflows
The 3 types of canaries available by StackGuard are:
- Terminator canaries : a canary that contains NULL(0x00), CR (0x0d), LF (0x0a), and EOF (0xff). These bytes mostly terminate most string operations in C (depends on the function used aka read() vs strcpy())
- Random canaries : just a random number uknown to the attacker
- random XOR canaries: XOR of a random value and the saved return address.
-fstack-protector
-fstack-protector-all
-fstack-protector-strong
-fstack-protector-explicit
clang and stack protection:
Clang supports mostly the same flags as GCC and in Clang 13 we have SafeStack.
SafeStack is an instrumentation pass that protects programs against attacks based on stack buffer overflows, without introducing any measurable performance overhead
clang --help | grep stack-protector
-fno-stack-protector Disable the use of stack protectors
-fstack-protector-all Force the usage of stack protectors for all functions
-fstack-protector-strong
-fstack-protector Enable stack protectors for functions potentially vulnerable to stack smashing
3.) NX: In a Von-Neumann-Architecture code and data is not seperated, thats why data, if this bit is not set can be executed,like data that has been put on the stack. It is short for “No eXecute” aka “Data Execution Prevention” or DEP. It marks areas of the program as non executable. This implies that stored input or data cannot be executed as code. . This is significant because it prevents attackers from being able to call custom shellcode that they have stored on the stack or in a global variable.
GCC: -z,noexecstack
Clang: ??
4.) PIE aka “Position Independent Executable”:
This indicates that the executable was built in such a way (PIE) that the ``text’’ section of the program can be relocated in memory. To take full advantage of this feature, the executing kernel must support text Address Space Layout Randomization (ASLR).
A question that always appears then is: “Difference between pic Vs pie”
GCC: -fpie or -fPIE and -fpic or -fPIC
clang: -fPIC and -fPIE but be sure to use -target (eg x86_64 otherwise it might silently drop PIE/PIC) so sth like: ‘-fpie -target x86_64’
Side note on defaults GCC vs CLANG here:
* clang print.c -o print_clang
* gcc print.c -o print_gcc
Watch out for the defaults for the PIE setting on Linux! (⊙.☉)7
This is based on "clang — version" --> Debian clang version 11.0.1–2
On *BSD it produces “PIE” by default.
5.) FORTIFY aka use Fortify Source functions.
FORTIFY_SOURCE is a GCC and GLIBC security feature that attempts to detect certain classes of buffer overflows. Its enabled by default on most Linux platforms.-> https://stackoverflow.com/tags/fortify-source/info
and in depth discussion here: “Enhance application security with FORTIFY_SOURCE”
GCC: -D_FORTIFY_SOURCE=2
CLANG: same as GCC but “But do we get the extra protection?”
6.) Control flow integrity, will be put in another post too, as for this some more background is needed too ٩(๏_๏)۶
Thats all for today (◠﹏◠)
Have a great day ahead and thanks for reading ;-)
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Sources (used besides the links given in the text):