Resources

People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!

This shouldn't have happened: A vulnerability postmortem - 688

Tavis Ormandy - Project Zero (P0)Posted 4 Years Ago
  • The author of this post found an extremely straight forward bug that has been around for quite some time! The first part of the article explains the bug, then the author dives into why this wasn't discovered and how we can find these types of bugs in the future.
  • Network Security Services (NSS) is a cryptographic library that is maintained by Mozilla. When you verify an ASN.1 encoded digital signature, NSS will create a VFYContext structure to store the necessary data. This includes things like the public key, the hash algorithm, and the digital signature.
  • In this implementation, the RSA signature has a maximum size of 2048 bytes which is 16384 bits. What happens if you use something bigger than this? Memory corruption! An attacker controls the data and the size that gets put into a memcpy for a fixed sized buffer.
  • The bug is fairly straight forward; copying data into a fixed size buffer without any sanity checks. The author then asks "How did this slip through the cracks?" Mozilla does nightly fuzzing of this library, ASAN could have detected this easily, lots of people look over the code... so, what went wrong? The author has three points for this.
  • The author of this post actually found the bug through fuzzing. They were experimenting with a different coverage method than block coverage. One of these was stack coverage, which monitoring the stack during execution to find different paths this way. The other way was object isolation, which is a way to randomly permute templated data,
  • First, the library is missing end-to-end testing. NSS is a modular library, meaning that each component is fuzzed individually. For instance, QuickDER is tested ONLY by creating and deleting objects, but never actually uses them. Since the buggy code only happened when verifying a signature, the fuzzer would have never caught it.
  • Another issue is that fuzzers typically cap themselves on the size of inputs in order to be faster and get coverage quicker. In the case of this library, the size cap was 10,000 bytes. However, these limits are arbitrary and may lead to missed findings, as lots of vulnerabilities occur at the extremes.
  • All of the NSS fuzzers are represented in combined coverage metrics by oss-fuzz instead of individual coverage. This data was misleading, as the vulnerable code is fuzzed extensively but by fuzzers that could not possibly generate a relevant input. This is because the testing uses hardcoded certificates, which is where this code was at.
  • Overall, the bug was really simple. The analysis of why such a simple bug lived so long in the code base was fascinating. To team, it means getting as much real coverage as possible and leading the randomization algorithms to its thing. Consider all of the possible cases where something could be used and ensure that the fuzzer can do this.