We didn’t realize that we were terrible bloggers until it was far too late to do anything about it.
Effective blogging probably has many components, but I believe one of the key tactics is to state a controversial opinion that will necessarily highlight a point of conflict between two reasonably sized groups of people. (I believe you get bonus points if one of the groups of people is actually completely fictional. You get even more bonus points if the point of “conflict” is actually a subtle trick of language that causes a group of people that agree to argue with themselves.) If done artfully, this generally results in much Internet chaos, which I think we can all agree is a lot of fun for everyone.
So, besides being terribly lazy at times, we’re just not the most opinionated guys in the world. Personally, I think having only one opinion is just intellectually lazy, and that you should try to have at least three or four for any given issue. Mark’s opinions tend to center around vegemite, currency hedging strategies, and the extent to which using Hex-Rays makes you “suck at Internet.” Justin’s opinions are classified and have to go through pre-pub review. So far, all we’ve gotten out of him is that he likes Batman. (I suspect this is because he actually *is* Batman, but that’s a topic for our next scheduled post in Q3 2009.)
Anyway, the point of this rambling pre-amble is three-fold:
1. Justin is probably Batman.
2. A page long preamble that doesn’t mention the point of the article is almost certainly not a technique of effective blogging.
3. I do have several strong opinions about software security and thought I’d give proper blogging a shot.
So, here goes. One of the things that offends my delicate sensitivities is this idea:
Software vulnerabilities can be divided into two classes:
bugs and
flaws. Roughly 50% of software vulnerabilities are bugs, and 50% are flaws. Arming the Straw Man
I’m walking into an automatic-weapon fight carrying a butter knife, and these are not straw men wielding the guns, but several accomplished pioneers of our field. Specifically, Gary McGraw has written a series of excellent books on software security, and I’d recommend you read all of them. He introduces his own nomenclature for tackling the software security problem, in which he divides software defects into bugs and flaws. Debates are won and lost based on definitions, and I play to lose, so I’ll try to give a reasonable summary of his definitions:
First, in McGraw’s terminology, defects are the set of issues in software that cause problems. This is what we (the enlightened common man) call software bugs in general. Basically, everything from Microsoft Office crashing on you causing you to lose a few hours work, to your VPN concentrator getting bored with executing the same code day in and day out and trying on some new code that a mysterious Internet buddy gave it. (read: Mark Dowd)
Bugs, in McGraw’s nomenclature, are what we generally call implementation flaws. Basically, these are technical problems in the program that result from idiosyncrasies of the technical underpinnings that comprise an application and its run-time environment. These include buffer overflows, format strings, resource leaks, off-by-ones, misuse of API calls, and simple race conditions. One of the criteria that McGraw uses to help explain these is that they can be discovered with limited context within code, as you don’t need to know what the code is actually doing or understand it at higher layers of abstraction.
Flaws, in McGraw’s nomenclature, are what we call design or architecture flaws. These are problems at a higher level of abstraction such as artifacts of subtle object-oriented run-time mechanisms, high-coupling/low-cohesion designs, issues with privilege, issues with failure conditions (e.g. failing open), issues with type safety, auditing issues, authentication and/or authorization problems, or incorrect use of crypto or obfuscation.
Kicking the Giant You’re Standing on
Here are the reasons why I think this is at least 64% wrong:
1. The term “design flaw” is too vague, and it encapsulates so much ground that it’s hard to tell what actually is and isn’t a design flaw.
I would assert that actual design vulnerabilities aren’t extremely common. In my mind, this is a security problem which, given sufficient design documentation like a DFD, you could point to and say “this is a security hole that violates the security policy of the system.” Of course, when they are present, they are usually *really* bad and hard to fix.
On the other hand, bad designs are extremely common. Given the same documentation and DFD, you can almost always know exactly where you are likely to find security problems. For most business software, the choice of language itself can be a bad design choice. Why outsource an application and demand that it be written in C when any higher-level language is about 2000 times less likely to be riddled with security flaws? (Full-disclosure: C is the best programming language ever.)
In my experience, it’s not super often that I can point to documentation and say “hey, your algorithm for debiting accounts is flawed,” or “hey, all your authentication is client-side,” or “hey, this piece runs with privilege and its internal interface is exposed to the network.” It happens plenty enough, but it’s not ubiquitous. (Crypto is the one place where my argument falls apart, as for some reason, crypto algorithms usually end up being placed in pseudo-code in design-level documentation. And, it’s usually completely fail, or at the least, you can tell where they’ve ventured into territory only suitable for mathematicians and particle physicists.)
On the other hand, you can almost always see manifest evidence of bad design. Especially in over-engineered J2EE business apps that are probably more complex than the software driving the space shuttle. There is no doubt that bad design creates security holes, and knowing why a design is bad tells you where to look.
2. 50% / 50% is a clear example of Marcus Ranum’s “bad science.”
Since it’s hard to pin down what design flaws are, the claim that there is a 50/50 split between design and implementation flaws seems fairly meaningless in reality. In my experience, in a large closed-source business application, I might find one or two actual design problems that let me break into a computer or steal data, where I’ll typically find 30 implementation level problems with similar consequences. That said, if I count bad design in general as a design flaw, then I guess you could argue a good design would eliminate most of the implementation flaws. In theory. In practice, it would probably swap out the existing 30 implementation flaws for 5 new ones.
Another way to put it would be that every implementation flaw is a design flaw, as von Neumann and Turing were short-sighted and were probably pre-occupied with all that war stuff.
3. Language is powerful. Anchoring to the two extremes downplays the middle.
First of all, it’s readily obvious to anyone that does vulnerability research or application security consulting for a living that software vulnerabilities live on a continuum of abstraction. While some flaws are easily definable as a design mistake or a straight out strcpy() style implementation vulnerability, most of the time, things aren’t that simple.
McGraw makes this point, as do other authors (ourselves included). However, if we’re going to design our own language, we should acknowledge that language is powerful. Anchoring the continuum to these two definitions completely minimalizes the substantial middle ground. The best word we have for this middle ground that I know of is logic vulnerability, but that’s not quite encompassing enough.
4. The auditing thought process is the same.
I’ve audited for both classes of issues and everything in between. One thing I’ve observed is that the thought process is very similar. You have a system, which has data-flow and control-flow, which turns into an algorithmic system of logic. You have to brainstorm pathological ideas and trace them through the system. Or, you observe potentially problematic elements or nuances in the system and try to trace in both directions to see if you can leverage them to do something “unusual.”
When it’s most fun is when you observe multiple atomic actions you can perform in the system, both legitimate and some born of mistake (like a subtle logic oversight). You then use those actions to form a system of logic of your own and in essence create your own “evil” language. You try to find some way of achieving an end by stringing all these atomic actions together programmatically. If you’ve spent a lot of time breaking systems, you probably know what I mean. If not, I assure you that I’m not just making up words to sound cool. (Yeah, this is what I think cool sounds like. The ladies love it.)
Comparing auditing assembly to auditing C is another good example. These are essentially similar tasks but performed at a different layer of abstraction. There’s myriad technical differences in what you do and how you do it, but the actual thought processes are pretty much the same.
5. I didn’t think of it.
I’d probably be arguing the other side if I’d thought of this first. ;>
Straw Men Hate 0day
So, the real thing that bothers me about the bugs/flaw language isn’t so much its usefulness as a teaching tool and metaphor. I think it is useful and does draw an important distinction. The thing that bothers me is the subtext of people that employ this terminology. More numbered arguments:
1. It’s overloaded to overemphasize the importance of automated analysis tools.
This distinction feeds into a world-view that you can divide software security into two domains: those problems that need security professionals to identify and solve, and those problems that will/can be solved by automation.
In essence, hire a team of experts to find your design bugs, and then run some tools to handle the implementation bugs.
Tools are great and you should use every one that makes you more effective. (Or, if possible, roll them into your development/build process.) But, you still need experts to find the implementation bugs, whether or not they use tools. (I don’t just mean consultants; some internal security teams I’ve run into are unaccountably scary.) They should use tools to help them be thorough, but if you get a chance to hire a world-class auditor and he tells you that he doesn’t use tools beyond one’s he’s written, hire him. :> (If there’s an employee referral bonus, I will expect my fair cut.)
2. At its worst, it’s a mechanism for excusing away a lack of competence.
In my experience, vulnerability researchers tend to pride themselves on two things: finding vulnerabilities in code that really matters (especially if it has been heavily audited), and finding obscure and subtle vulnerabilities that are sufficiently complicated that it’s hard to describe them in words without a few Visio diagrams. (Pro-tip: never open Visio documents from vulnerability researchers. Buy a whiteboard.)
Application security consultants tend to pride themselves on related things. You get dropped in the middle of a million line application with a team of potentially hostile developers and you do your best to quickly assemble a mental model of how a business works, what the software does, and how it can be attacked. You never have even remotely close to enough time, so you have to make your best Herculean effort to try and find all of the problems you can across all layers of abstraction. If you’re good at it, this necessarily causes you to discard your pre-conceived notions and find strategies that work. You have to be both deep and broad, and if you miss something that shows up on Bugtraq a month later, well, you better hope your sales guys managed to get across the nuance of how it’s impossible to prove a negative.
Any good application security consultant or vulnerability researcher better be able to find both implementation and design flaws, and everything in between.
To put it another way, if I needed an application security consultant and had the choice between hiring someone that could find security vulnerabilities by reverse engineering or hiring someone who was fully versed in design and policy review, I’d hire both of them. But if I only had one head-count, I’d hire the reverser and tell him “you have a lot of not-fun crap to learn, but it’s basically the same not-fun crap you do now, just a little easier.”
3. Implementation flaws are the ball-game.
If your standard for a security hole is:
“something that lets me break into a computer”
Then, implementation flaws are the ball-game. They don’t care much about how great your design is; they transcend design. If you can send the right bytes to an interface and pop arbitrary code execution, your adversary wins. If it’s got layers of defense, that’s great, but those layers better not have any implementation flaws either or you’ve just made the game that much more exciting for your adversary.
They are the trump card. If you overweight design flaws and minimize implementation flaws, you do it at your own peril.