Compiler options for creating secure DNS Server binaries (on Linux)
DNS server, as these processes recieving data from untrusted sources in the network, are vulnerable for attacks that exploit security proplems in the DNS servers program code. Special crafted DNS packets can trigger a software bug in the DNS servers code and which will execute code contained in the received data, allowing the attacker to change the behavior of the DNS software or even break into the operating system running the server.
Modern Linux systems contain exploit mitigation techniques that make it harder for attackers to sucessfully launch such attack. However most of this functions are not enabled by default, but must be enabled during compile time. This is especially imnportant if the DNS server software is custom compiled and not taken from the Linux distribution vendor. But even the binaries supplied by a Linux distribution might not have all the exploit mitigation security functions enabled.
The screenshot below shows a BIND nameserver binary (named) with only some of the security functions enabled, and an Unbound nameserver binary that has all of the functions enabled:
The functions in detail:
RELRO rearranges the data sections inside an ELF (Linux executable file format) executable. It also marks certain areas as 'read-only' so that these data structures cannot be overwritten while the process is running.
Details about RELRO can be found in the blog post RELRO - A (not so well known) Memory Corruption Mitigation Technique.
There are two flavors of RELRO, 'partial' and 'full'. Only 'full RELRO' offers all security measures and is recommended.
A STACK CANARY is a special datastructure with a distinct bit-pattern that is placed in front of important data on the stack, for example in front of the return address of an subroutine call. A popular attack is to overwrite (using a buffer overflow or similar problems) the return address of a subroutine call, so that the execution process is redirected to execute program code injected by the attacker.
When using a stack canary, the operating system will check if the bit pattern placed in front of the stack datastructure is still intact (and not overwritten). Only if this is true, the jump through the return address will be taken. The named 'stack canary' comes from canary birds used in early mining operations, where the birds where used as in indicator that the air under ground is becoming foul. See GCC Stack-Smashing Protector (ProPolice) on how the canary is implemented in the GCC compiler suite.
NX enabled refers to the NX (non-execute) or XD (execute disable) flags found
in modern x86 CPUs (Intel and AMD). The NX flag are used to mark memory areas
that only contain data (and no program code) as 'off-limit' for the CPUs
instruction fetch. The data stored in this areas marked cannot be executed
as a program by the CPU. Because this flag is implemented directly in the CPU,
it has no overhead compared to exploit mitigation functions implemented in
software. Some Linux systems running on hardware that does not support
a 'no-execute' flag emulate this function in software.
See Wikipedia on NX bit.
PIE - Position independent code
PIE stands for 'Position Independent Executable' and describes a function where the operating system can load certain parts of the application at random positions inside the computers address space. In some attacks the attacker needs to know beforehand on which memory location a datastructure will be loaded (e.g. to jump into code that has been written using a buffer overflow). By having the operating system load the program code into different locations every time, the attacker cannot predict the memory location, which makes it harder to write a sucessful exploit.
In addition to the technologies above, the GCC C-Compiler can analyse the source code to be compiled and detect certain insecure sections (that might create a security problem). The compiler will replace the insecure function calls with special hardened code that will perform extra runtime checks while the process is executed. This is called FORTIFY SOURCE.
Compiler- and Linker-Flags
To enable these exploit mitigation functions in compiled binaries, special flags must be specified for the compiler (gcc) and linker.
- RELRO: LDLFAGS="-z relro -z now"
- STACK CANARY: CFLAGS="-fstack-protector" LDFLAGS="-fstack-protector"
- PIE/PIC: CFLAGS="-fPIE -fPIC" LDFLAGS="-fPIC -pie"
- NX: is enabled on the OS and BIOS level, but can be disabled in the ELF file. It should be enabled by default if not manually disabled for a binary.
- FORTHFY-SOURCE: CFLAGS="-O2 -D_FORTIFY_SOURCE=2"
example linker flags (32bit/64bit):
LDFLAGS="$LDFLAGS -fPIC -pie -z relro -z now -fstack-protector"
example c-compiler flags (32bit):
CFLAGS="-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector -fPIE -fPIC --param=ssp-buffer-size=4 -m32 -march=i686 -mtune=i686 -fasynchronous-unwind-tables"
example c-compiler flags (64 bit):
CFLAGS="-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector -fPIE -fPIC --param=ssp-buffer-size=4 -m64 -mtune=generic"
Of course the exploit mitigation techniques described here are also valid for all networked applicartions (such as SSH, webserver, NTP ...), not only for DNS server. But this is the DNS workshop ...
- NX bit
- Security features in Ubuntu Linux>
- Debian Hardining
- Basics of stack-smashing attacks and defenses against them
- Position Independent Code internals
- Buffer overflow and you
- Protections against buffer overflow
- Disabling the NX bit for specific apps
- Linux PAX security extension