Learn about binary hardening with hardening-check

In my last post, I wrote about using Radare2 to measure cyclomatic complexity, giving us a metric of the number of “moving parts” in a binary. From a risk quantification point of view, this is important because we assume that a more complicated program will be easier to get to misbehave.

But there are a lot of binaries in a Linux install. Let’s do a find against / and see for ourselves. Again, I find myself on my Macbook, so let’s do this from a docker container because it’ll be quicker than a VM. This assumes you already have Docker installed and configured.

mb:~ jason$ docker run --rm -ti fedora bash
[root@0600e63539d7 /]# dnf install -q -y file findutils
[root@0600e63539d7 /]# find / -exec file {} \; | grep -i elf | wc -l

Over a thousand, even in a small docker image! Now imagine you’re a security researcher, or maybe a 1337 hax0r, and you want to find a new vulnerability in one of those binaries. Which ones do you try to attack?

In this scenario, we need to be selective about which binaries we want to target, because fuzzing is time consuming. So which ones will give us the best bang for our buck, so to speak? We want to look for low-hanging fruit, and in order to do that we need to identify binaries that are, basically, poorly built.

This process — looking at binaries, scoring them in terms of how much effort it would take to successfully fuzz them and find a new 0-day — is what the Cyber-ITL is all about. And this is what we want to duplicate in the open source world with the Fedora Cyber Test Lab.

There are a number of mechanisms that have been built into Linux over the years to frustrate this process. I find a good way to learn about those mechanisms is to look at the code for a tool called hardening-check.

hardening-check was written by an a kernel security engineer at Google, Kees Cook, who, from the look of his Twitter profile, is a bit of a Stand Alone Complex fan. This tool came out around 2009, during which time Kees was working as an Ubuntu security engineer. Since then hardening-check has been picked up by other distros, and is just super-handy.

(In the next several posts, we’ll be referring to the hardening-check Perl source code, which is version controlled here.)

First, let’s install and run the tool to get a feel for it. We’ll also install gcc for the next example.

mb:~ jason$ docker run --rm -ti fedora bash
[root@59c1a1a14181 /]# dnf install -q -y hardening-check gcc
[root@59c1a1a14181 /]# hardening-check /bin/ls
 Position Independent Executable: yes
 Stack protected: yes
 Fortify Source functions: yes (some protected functions found)
 Read-only relocations: yes
 Immediate binding: yes

Alright, that looks pretty good. Now let’s write another hello world program, but this time we’re going to deliberately use a notoriously unsafe function.

#include <stdio.h>

int main() {
  char str1[12] = "hello world";
  char str2[12];
  sprintf(str2, "%s", str1);
  return 0;

For now, we compile it without any extra flags, then run hardening check.

[root@59c1a1a14181 /]# gcc hello_world.c
[root@59c1a1a14181 /]# hardening-check a.out
 Position Independent Executable: no, normal executable!
 Stack protected: no, not found!
 Fortify Source functions: no, only unprotected functions found!
 Read-only relocations: yes
 Immediate binding: no, not found!

Not so great. But we can ask gcc to help us out.

[root@59c1a1a14181 /]# gcc -D_FORTIFY_SOURCE=2 -O2 -fpic -pie -z now -fstack-protector-all hello_world.c
[root@59c1a1a14181 /]# hardening-check a.out
 Position Independent Executable: yes
 Stack protected: yes
 Fortify Source functions: yes
 Read-only relocations: yes
 Immediate binding: yes

That’s better. Now our silly little program is much harder to leverage in an attack.

This brings up a lot of questions, though. Why isn’t every binary compiled with those flags? Why don’t we just tweak gcc so it always applies those protections by default? For that matter, what do all those checks mean? Can they be defeated by attackers?

Stay tuned as we dig into each of those questions, and explore how they apply to our Cyber Test Lab.