You wouldn’t think how many bugs one -accidentally- places into binaries, digging around in a compiler, while trying to *find* glitches in the source code, or to develop mitigations. Mischievous would one be, if they decided this were their goal.
We will start out looking at some of the more exotic segfaults, encountered while trying to improve binary output with all the best intentions. We’ll stick to Linux, and if I was a pop star, my biggest hits would be “The ELF and princess cyber”, “PIC me a flower”, “Its GOT to PLT perrrfect” and “(Tail) Call me, maybe”.
But thank god I’m not. Instead we will investigate how an attacker could go about introducing bugs into binaries with the help of a compiler. Focusing on GCC, cause LLVM is for hipsters. GCC stands for GNU compiler collection, and at a 10k-foot distance has a fairly simple and modular structure. But, the deeper we dive, the more the complexity freaks among us get what they desire. We will have a look at the different stages and passes of the compiler, where we can possibly tap into, and what our tools at hand are, beneath a jungle of structs and macros.
The goal of this journey is to explore the questions; how many bugs could possibly be worked into innocent source code, so the thing still compiles and runs, just not “too” well? What are the trade-offs between stealth and effectiveness? Avenues to explore range from rough measures such as removing sanitization code, changing buffer sizes or data types, to more fine grained approaches such as carefully “optimizing” sensitive operations, fiddling with the architecture specific machine definitions or creatively re-balancing the stack. There will be demos, oh yeah and also, ideas on how to find an attacker’s evil little modifications.
But end of the day, the moral of the story would be, keep the crooks out of your build environment.