Live data from Hacker News

Zeroing buffers is insufficient

daemonology.net

41–50 of 134 posts

Re: Zeroing buffers is insufficient

#41
Every time I read one of these posts about a clever "attack vector", how something can be gleaned from this special register, or a timing attack, somesuch, I remember about a theory that the sound of a dinosaurs scream can be extracted from the waves impact made on a rocks crystal structure.

I googled pretty hard for real life example uses of a timing attack, and now using of stale data on the register, but couldn't find anything. Does anyone know of examples of this actually being done?

Re: Zeroing buffers is insufficient

#42

I don't completely understand the C spec. Would the following approach work for zeroing a buffer? 1) Zero the buffer. 2) Check that the buffer is completely zeroed. 3) If you found any non-zeros in the buffer, return an error. Is the compiler still allowed to optimize away the zeroing in this case?

> Is the compiler still allowed to optimize away the zeroing in this case?

Yes, completely. In the snippet below, the compiler is allowed to eliminate all code after “leave secrets in array c”.

  {
    char c[2];
    ... /* leave secrets in array c */
    memset(c, 0, 2);
    c[0] = 0;
    c[1] = 0;
    memset(c, 0, 2);
    if (c[0] || c[1]) exit 1;
  }
The compiler is also allowed to compile the last three instructions below as if they were “return 0;”

  {
    char c[2];
    ... /* leave secrets in array c */
    c[0] = 0;
    c[1] = 0;
    return c[0] + c[1];
  }

Re: Zeroing buffers is insufficient

#43

Please, assembly is OK. It's not even magic or special wizardry. My dad programmed and maintained insurance industry applications in assembly side by side with many other normal office workers for decades. Assembly is OK.

Assembly is bad for auditability, which is important in crypto to prevent subtle errors.

As a seasoned and experienced reverse-engineer myself, I'm (genuinely) curious where you got that impression. Do you find it unapproachable?

Assembly is the simplest language you can write a computer program in, for a certain very textbook definition of "simple" - it's just that you actually have to do everything by hand that you normally wouldn't. And yes, that can be a pain in the ass, and yes, you do have to watch out for not seeing the wood for the trees - but one thing it most definitely is, is auditable.

Bearing in mind, say, the utter briar-patch that is OpenSSL: a crufty intractably complex library written in a high-level language with myriad compiler bug workarounds, compatibility kludges and where - despite it being open source, and "many eyes making bugs shallow" - few eyes ever actually looked, or saw, or wanted to see, and when attention was finally paid to it, it was found wanting... might not assembly be perhaps better for a compact, high-assurance crypto library? Radical, I know, but perhaps an approach that's worthy of consideration.

I understand you may well be more familiar with high-level languages, and I don't know if you're confident about your ability to audit that - but I must point out, if you're auditing it from source, you're trusting the compiler to faithfully translate it. So to actually audit the code, you need to include the compiler in that audit. Compilers have (lots of) bugs and oversights too (lots of OpenSSL cruft is compiler bug workarounds, it seems?): as the article points out, existing compilers just weren't really designed to accommodate writing secure code.

Meanwhile an assembler makes a direct translation from source assembly to object machine code - that is deterministic (a perniciously-hard process with compilers) and much more easily, and automatically, auditable and indeed directly reversible.

To be clear, I'm not suggesting we replace, say, libsodium with something written in assembly language tomorrow! There are good high-level language implementations. And inline assembly is already used in some places for certain functions, including this exact one (zeroing memory), to try to minimise the compiler second-guessing us. But as the article points out, that approach only takes us so far, and it's something we need to be guarded against when trying to write secure code.

Re: Zeroing buffers is insufficient

#44

Every time I read one of these posts about a clever "attack vector", how something can be gleaned from this special register, or a timing attack, somesuch, I remember about a theory that the sound of a dinosaurs scream can be extracted from the waves impact made on a rocks crystal structure. I googled pretty hard for real life example uses of a timing attack, and now using of stale data on the register, but couldn't…

These types of attacks though only require one person to create a system that can reliably exploit them, and then the vulnerability will be in the wild and a more significant problem. Pulling off this type of attack is difficult, but you only need one piece of malware that has a reliable way to exploit this in a general case and then it becomes available to every script kiddie who finds some motivation for stealing private keys.

These type of attacks also might become more of a problem as more sensitive computation is done on shared machines (IE cloud compute).

So, while there's no reason to panic because these security features aren't implemented hardly anywhere, you can't let the issues sit unaddressed for long periods of time.

Re: Zeroing buffers is insufficient

#45
post #30

I don't think this can be a language feature. It's more a platform thing: Why is keeping key material around on a stack or in extra CPU registers a security risk? It's because someone has access to the hardware you're running on. (Note that the plain-text is just as leaky as the key material. Yike!) So stop doing that. Have a low-level system service (e.g., a hypervisor with well-defined isolation) do your crypto ope…

This is also why dedicated cryptoprocessors exist, with special features for attack resistance; I'm not completely certain about this, but I'd think the software running on those does not have to zero memory containing keys, because the whole environment that said software runs in has been secured from the outside already, and if it's possible to read any memory or run untrusted code from outside on those without bei…

Having seen a few existing designs of those, up-close and personal - actually they do have to worry about zeroisation, quite an awful lot.

And sometimes they don't worry enough either. They ought to fail a FIPS-style audit for that. But, well... they ought not to contain proprietary LFSR "crypto" algorithms, either. They are not as well audited, or as publicly designed, as they ought to be: many are as black-box closed-source as they could possibly be.

They tend to be based on extraordinarily old architectures with new bits glued on - think Intel 8051, that kind of era. If you're really lucky you might get an ARM, or at least a Thumb. People making them are notoriously hyper-conservative (most don't support ECC yet, and many don't even go above RSA-2048 or SHA-1 without going to firmware), and minimise any changes, perhaps for cost reasons, the effects of which are not always positive (actually, CFRG are discussing that general area right now in the context of side-channnel defences for elliptic-curve crypto).

So, how would you think that environment translates to writing secure firmware, or designing secure, state-of-the-art hardware? ;-)

Re: Zeroing buffers is insufficient

#46
post #25

Anything sent over HTTP(S), such as your credit card numbers and passwords, likely already passes through generic HTTP processing code which doesn't securely erase anything (for sure if you're using separate SSL termination). Anything processed in an interpreted or memory safe language puts secure erasure outside of your reach entirely. Afaict there's no generic solution to these problems. 99.9% of what these code pa…

Some of this can be addressed by never giving sensitive data to remote servers. This wouldn't work for credit cards, but with Bitcoin you never need to let a non-bitcoin library touch your private key, because that's not going over https.

Similarly, if you encrypt all of your information from within a safe library before handing it out to unsafe libraries, they can't leak anything. This can add overhead and redundant encryption (and you still need to trust that the remote server processing your data is safe), but there are steps you can take to be more safe.

Re: Zeroing buffers is insufficient

#47
post #37

Earlier quoted context omitted.

Sadly, I know that only too well: hence my "alas, microcode" comment! A prefix or mode or something which allows code to handle secure data and it gets constant-time multipliers, for example, or true µop-level register zeroisation, would be handy, but also close to unverifiable - we just have to sort of trust it, which sucks. Until then, we do the best we can with turtles all the way down. Software running under that…

If I wanted to read CPU registers from the outside, there's an easy way: JTAG. You should be able to halt the CPU, read (and modify!) the registers, and resume the CPU. That should be possible even on x86, though on x86 the relevant documentation is probably hard to find. For some ARM processors, it should be as easy as installing openocd. Of course, JTAG requires physical access to plug the debugging cable, which pu…

I can't believe I'd forgotten about JTAG! Yes, that's definitely more viable than decapping! Same completely-doomed threat model though ("attacker has physical access, can do anything they want and take as long as they need").

Sorry, I've been dealing with a few things more recently which, uh, haven't been quite so accommodating to analysis.

Re: Zeroing buffers is insufficient

#48
post #44

Every time I read one of these posts about a clever "attack vector", how something can be gleaned from this special register, or a timing attack, somesuch, I remember about a theory that the sound of a dinosaurs scream can be extracted from the waves impact made on a rocks crystal structure. I googled pretty hard for real life example uses of a timing attack, and now using of stale data on the register, but couldn't…

These types of attacks though only require one person to create a system that can reliably exploit them, and then the vulnerability will be in the wild and a more significant problem. Pulling off this type of attack is difficult, but you only need one piece of malware that has a reliable way to exploit this in a general case and then it becomes available to every script kiddie who finds some motivation for stealing p…

But there is a whole range of potential issues. Or things compiler developers can do. As any task, they should be sorted, weighted by ease of exploitation and ease of solving. What I suspect, and I'm just curious to see if I am wrong, is that developers postulate vulnerabilities that real hackers would never bother with, and miss what they really go for, such as trivial mistakes, such as forgetting bounds checking.

So, I've seen a lot of (conceptually) trivial exploits and combinations of trivial exploits, but I would love to see a real world example of someone collecting enough information from an 'bad RNG', registers, or timing, to do anything with it.

Re: Zeroing buffers is insufficient

#49
post #9

WRT the AESNI leaking information in the XMM registers, wouldn't starting a fake AES decryption solve the problem? Also, wouldn't a wrapper function that performs the AES decryption and then manually zeroes the registers be a good enough work around?

If you're using AES-NI, you're already using an intrinsic. I haven't yet met a compiler "smart" enough to recognise an AES implementation and replace it with AES-NI, and god, I hope I never do.

Yes, you probably ought to be clearing xmm* registers touched by it, and that would I hope be good enough.

The point in the article about compiled code very seldom touching xmm* so that if you don't wipe it - is doing so currently common practice? I haven't checked, but I feel like that would be something that needs checking! - it's hanging around and you might leak it, is completely valid, however.

Re: Zeroing buffers is insufficient

#50

Every time I read one of these posts about a clever "attack vector", how something can be gleaned from this special register, or a timing attack, somesuch, I remember about a theory that the sound of a dinosaurs scream can be extracted from the waves impact made on a rocks crystal structure. I googled pretty hard for real life example uses of a timing attack, and now using of stale data on the register, but couldn't…

[deleted]
Post reply on HN