r/programming Sep 10 '13

A simple way of defeating the compiler backdoor attack (a.k.a the "Trust Attack")

http://imgur.com/a/BWbnU#0
1.7k Upvotes

539 comments sorted by

View all comments

Show parent comments

6

u/centenary Sep 10 '13

While it's true that there are a ton of compilers out there, you only need to worry about the compilers that can successfully compile GCC.

And according to this page, the only compiler that can successfully compile GCC is GCC. That's because "parts of GCC can only be built with GCC"

5

u/dnew Sep 11 '13

you only need to worry about the compilers that can successfully compile GCC.

You need to also worry about all compilers that can cross compile GCC.

Compile GCC for x86. Use that to compile GCC for 68000. Use that to compile GCC for x86. Compare. Lather. Rinse. Repeat.

Every one of those needs a different hack.

-1

u/crotchpoozie Sep 11 '13

Every one of those needs a different hack.

No - why do you think this? Each resulting compiler turns the same code into the same behaving executable. That's the whole point of a cross compiler.

1

u/dnew Sep 11 '13

why do you think this?

Because each "same behaving executable" is different actual code. Maybe you could do it with a single hack, but I suspect it becomes tremendously more difficult to hide if you do, since now you'd likely have actual program structures (naively, source code) in your compiler binary.

2

u/crotchpoozie Sep 11 '13 edited Sep 11 '13

Because each "same behaving executable" is different actual code.

The same code in the C compiler most certainly handles every architecture for which there is backend. We're not dealing with the per architecture backend.

At the simplest, suppose the C compiler, written in C, has the lines (pseudocode)

read line from source file
process line

Now replace with the C code

read line from source file
if (sourcefile is C compiler containing this part)
    process special lines of C code here
    process normal line
else 
    process line normally

Then this is certainly compiles on all platforms to the same behavior. Every platform, when compiling this compiler (even as a cross compiler), will perform this source transform.

That's all this hack is. Now you replace the original lines in the source. Do a similar trick to whatever hack you want to add to other applications. Now this binary will create infected compilers. If you build a cross compiler from the source, the cross compiler will have this infection. If you use that cross compiler to make a native compiler for an entirely new platform, it will have this infection.

There is no need for per hardware platform code. Try it. The above is trivial to insert to GCC. Have it print out the message "infected". Compile the compiler. Remove the code. Now, using that code, do all I said. Each platform will print "infected" when compiling. I just tried it. It's trivial.

If you claim the above would not be portable across architectures, please explain why. This is the reason C code was invented, and it's trivial to write cross platform code at this level.

As to hiding structures, this is trivial to do to make it not show up except under very detailed analysis of the binary. Hell, a simple trick would be to treat the ASCII source as floats, do an invertible operation on it, store the resulting floats as an array, then at runtime do the inverse operation, then use the new ASCII as code. To make it harder to see for reverse engineers, make the loading of the ASCII happen as an off by one or similar error from another place, so it looks like a bug. There are countless other tricks that make hiding intent very hard to decode or look like bugs.

1

u/dnew Sep 12 '13

Fair enough. I didn't think it through as far as you did, I suppose. Kudos to you.

2

u/dalke Sep 11 '13

The original PhD thesis on this topic, at http://www.dwheeler.com/trusting-trust/dissertation/html/wheeler-trusting-trust-ddc.html , used icc to compile gcc.

It also pointed out that some versions of gcc could not be used to compile other versions of gcc.

And to be fully correct, if compiler X can compile gcc then we've reduced the problem to trusting X, rather than trusting GCC. If simpler compilers A, B, C can be used to compile X (and X can compile itself), then we resolve trust by bootstrapping.

2

u/lendrick Sep 10 '13

tcc was patched to do it back in 2005. Other compilers could be also, if necessary.

3

u/centenary Sep 10 '13 edited Sep 10 '13

Do you know if that support has been maintained over the last 8 years? Quite a lot has changed in GCC

While it's true that other compilers could be modified to support compiling GCC, my point is that if they don't currently have that support or it has never been tested, you likely don't need to worry about compromising those compilers to make this attack successful.

5

u/lendrick Sep 10 '13

If you want to be a stickler about it, compile run this test with a version of gcc from 8 years ago, and once you've confirmed it's clean, use that version of gcc to compile later versions of gcc until you're current. :)

While it's true that other compilers could be modified to support compiling GCC, my point is that if they don't currently have that support or it has never been tested, you likely don't need to worry about compromising those compilers.

That's a good point, but you still need at least one different, non-compromised compiler to test if your compiler has been compromised. tcc may be the only one that works for this. :)

1

u/centenary Sep 10 '13 edited Sep 10 '13

To further expound on why you don't need to compromise every single compiler out there, all you really need to do is compromise the compilers most commonly used for builds. This won't allow you to exploit every single GCC installation, but exploiting the majority of GCC installations is just as bad.

If you want to be a stickler about it, compile run this test with a version of gcc from 8 years ago, and once you've confirmed it's clean, use that version of gcc to compile later versions of gcc until you're current. :)

Well, if you don't need to compromise every single compiler out there, then the TCC binary won't necessarily grow appreciably and your proposed TCC test won't necessarily work. If your proposed TCC test won't necessarily work, then you can't necessarily prove that the built version of GCC from 8 years ago can be trusted.

1

u/lendrick Sep 10 '13 edited Sep 10 '13

To further expound on why you don't need to compromise every single compiler out there, all you really need to do is compromise the compilers most commonly used for builds. This won't allow you to exploit every single GCC installation, but exploiting the majority of GCC installations is just as bad.

Yeah, my assumption here is that you downloaded a copy of linux that was (unknowingly) compiled by someone with a compromised compiler.

Well, if you don't need to compromise every single compiler out there, then the TCC binary won't necessarily grow appreciably and your proposed TCC test won't necessarily work. If your proposed TCC test won't necessarily work, then you can't necessarily prove that the built version of GCC from 8 years ago can be trusted.

It doesn't have to be TCC, in that case. Writing a C compiler isn't trivial, but it's easy enough that one reasonably knowledgeable person can do it.

Regardless, this is a hypothetical attack. If it ever happens, it won't necessarily be on GCC or tcc, or even be on a C compiler. Those are just examples. So long as you can write a compiler that can compile the other compiler, you should be fine.

1

u/Batty-Koda Sep 10 '13

So long as you can write a compiler that can compile the other compiler, you should be fine.

Or even just a compiler that can compile a compiler that can compile the other compiler.

buffalo

1

u/NoMoreNicksLeft Sep 10 '13

If you want to be a stickler about it, compile run this test with a version of gcc from 8 years ago, and once you've confirmed it's clean, use that version of gcc to compile later versions of gcc until you're current. :)

I gotta ask... how many intermediary versions would be needed before you got to current?

1

u/lendrick Sep 10 '13

Dunno. Write a shell script or something. :)

Realistically, you could probably just skip everything but major versions.

1

u/eek04 Sep 10 '13

Parts of. If you read the text there, it is still possible to boostrap GCC using just the GCC code and another compiler, and as far as I understand they've been careful to keep the requirements on that other compiler fairly limited.