e shtunë, 18 gusht 2007

Security Code Scanning with Microsoft PREFast

Overview

Probably one of the most useful security tools to come out of Microsoft, yet the least known and adopted is the PREFast tool. PREFast is a static source code security scanner, or in other words, PREFast is a scanning tool that takes source code as input and returns a list of potentially vulnerable code that could create risks to you and your customers. In the case of PREFast it takes in C/C++ source code and analyzes that code for common coding defects. Security defects by the way are one of several types of defects this tool can detect, so with PREFast you get more than just security code scanning. Did I also mention it's free?



I knew that would get your attention and now that I have it, it's important to understand that PREFast won't solve all your security problems, no one or even a series of tools can (I'll talk about PREFast's limitations later). What it will get you is an objective, repeatable, low-cost risk control to enforce a baseline that you can include in your security development practices.

Are there other security code scanners we could use to scan C/C++ code? Sure, but the beauty of Microsoft's PREFast is you get an enterprise-strength security code scanner without the enterprise-strength price.

In the rest of the article, I'll show you how to get PREFast, how to get started with it, and most importantly how to verify that it's working correctly.


Getting Microsoft PREFast Step-By-Step

As useful as PREFast is, it's notoriously one of the hardest tools to find (this probably explains its low rate of adoption). PREFast is not available as a standalone download, and in order to get it you need download it as part of the latest Microsoft Windows Driver Kits (WDKs) which itself involves several steps that sadly deters most users. In this section of this article, I'll show you step-by-step how to get your hands on PREFast.

Before we begin, you'll need a couple things: a DVD burner, a blank DVD-R disk and DVD burning software. Once you have the above ready, follow these steps to get the PREFast tool.


  • Step 1: Go to Microsoft Connect website.

  • Step 2: Sign in with your Microsoft Live ID account. If you don't have one you can sign up for one here.

  • Step 3: Click Available Connections on the left-side navigation bar.

  • Step 4: Look for Microsoft Windows Driver Kit (WDK) and Windows Logo Kit (WLK) link. Click Apply if you haven't already done so before.

  • Step 5: Fill out the registration screen details and click Continue.





  • Step 6: At this stage you should be signed-in and ready to download the appropriate WDK. To start, click the Connect Home link on the upper left side navigation menu.

  • Step 7: Click My Participations also on the left side navigation menu. You should see a table to lists your available connections.







  • Step 12: With luck, the transfer should start and once that's done you should have one very large ISO (short for disk image of an ISO 9660 filesystem) file. From here you can use any DVD disk burning software to write the ISO filesystem back onto a DVD disk. After that's done, run the install disk on the machine you wish to install PREFast onto.

  • Step 13: Install the WDK. PREFast automatically gets installed with the main build environment.






  • Step 14: Open up a build environment and verify that PREFast was installed correctly. To do this, press the Start Button, then Programs and look for the Windows Driver Kits folder. Click on this folder, then click on the folder WDK 6000, then click on the folder Build Environments and then click on your target operating system. For instance, if I am developing an application for Vista, then I'll want to click on the Windows Vista and Windows Server Longhorn folder. Finally choose the target build environment and a MS-DOS style command prompt should open. For example, if I want to develop for Windows Vista 32 bit, I would select Windows Vista and Windows Server Longhorn x86 Free Build Environment shortcut.







  • Step 1,000,000: We're finally at the last step and that is to verify that PREFast installed and is running correctly. To do this, just type prefast then Enter and you should see something like the following:



Fortunately we only have to do these steps once, and that we have PREFast installed and running, it's time to run it against some actual code.


Using PREFast


Now that we have PREFast installed and running on our system, let's give it a test run with some actual bad code. I've gone ahead and created some example vulnerable code for our discussion here. In the example pack you find an example of a strcpy buffer overrun (lines 13-22) and a format string vulnerability (lines 32-35), a make file and a sources file.

To use PREFast, we need to call on top of our compiler. The reason why this is is because PREFast works by "intercepting" calls to the compiler to determine if the code being compiled contains known defects. To do this simply open a build environment window (see Step 14 above), unpack the example files into a directory and from that directory type:

prefast build -cZ

The argument -cZ tells the build command to delete any previous object files (c) and not to check any dependencies (Z). After you give this command, PREFast kicks off, invokes the build command to start building our examples and after a small amount of time you should see something like this:





To view the results we have two options. View the results through the command line or via a graphical user interface (GUI). To view the results over the command-line, type:

prefast list






To view the results via the GUI, type:



prefast view





From the GUI you can double-click on the defect messages and it'll nicely highlight for you the area of code that generated the error and a little explanation.


At times you might see lots of defects and you can filter out only the ones you care about by pressing the filter button at the top of the GUI box and selecting the appropriate filters to view. After you've selected the desired defects, hit Apply and the GUI will trim the results to only the ones you care about.





That's it. That was the quick-and-dirty-get-you-up-and-running-now-without-having-to-ready-20-pages-of-documentation introduction to using PREFast! For most users this should be more than enough, but you want more Microsoft has published a more detailed step-by-step guide to using PREFast.



Verifying PREFast Scans


There's an old saying in management that goes something like this: if you can't measure it, it never happened. The same goes with code scanning: if you can't verify that the scan ran correctly or at all, it pretty much never happened. I know of one development team that learned this lesson the hard way, actually make that the very hard way. This team was nearing the planned release date of their product and decided to do some last minute due diligence with a security code scanner. Great, and good for them! The team however accidentally ran the code scanner with all checks turned off and so with a false clean bill of health from the scanner the product was released soon after. Not so great. Security researchers, good and bad, jumped all over the product and automated exploits soon followed. Sadly, careers were made (and some ruined) all at the expense of hacked customers.

Situations like these can be easily avoided. One trick that I use is to temporarily sprinkle the code bases that I am scanning with code that I know is:

  • Vulnerable and
  • Can be easily detected.

If you're one of my customers, you sometimes might hear me refer to it as beacon code, but the idea is if the code scanner, not just PREFast, doesn't pick up these little beacon code snippets then you know that the scanner is not operating properly. If the code scanner picks it up, then you know that scanner is working correctly and you have at least some level of assurance that the tool ran correctly (that sound you're hearing in the distance is the sound of all the security managers around the world like myself cheering).

So what does vulnerable beacon code look like? Here's the code I use when am doing C/C++ security assessment work for my customers. The beacon code is actually an off-by-one buffer overrun (explanation is in the code itself).

Add this code to as one of the sources (modify the sources file) to compile during code scan runs. It's important that you only include the beacon code during code scans and remove it right after, because if you leave it there some developer may mistakenly reference that code and now we've increased our risk. Granted off-by-one overruns are generally harder to exploit. That doesn't mean it's impossible by why take chances right? Run prefast again and you should see an error message corresponding to our beacon code pop-up.






And we're done! We've now verified that PREFast is indeed working and scanning the code!

Conclusion


Before we end our discussion of PREFast, it's important to highlight a couple important points about PREFast so that you know exactly what you are and aren't getting with this tool.

  • PREFast is not the best code scanning tool. In fact none of the tools available today or in the future are. The question you should be asking is "what are my organization's security requirements, and which tool best meets those requirements?". It's always important to first define those requirements otherwise you have no idea if the tool you're using is adding value or just wasting time. The tool (or tools) that matches those requirements best is the best tool for your organization. PREFast happens to match Microsoft security requirements, but may not necessarily match yours.

  • PREFast is just a tool. It can and should be used as part of any security process, but it should not be used as a replacement. I like to think of PREFast as steering wheel and a security process as a car. By itself, the steering wheel doesn't make a car, but without it the car won't function very well either.

  • PREFast is just a tool, part 2. PREFast and any other scanning tool can only detect what it's been designed to detect. So even if PREFast is gives you a clean report and you've verified that it's working you code might still be infested with defects. Hint: did you notice that in our PREFast there was no mention of a format string vulnerability? That's why we mitigate this particular risk with other controls such as expert analyst code review, penetration testing, etc. in case this particular control fails or is inadequate.

  • PREFast can be used as a good measuring (and beat) stick. If you're building out a security process and you want to first see how well or bad your organization is doing, PREFast is a good way to do that quickly. If you're a little further along and have a security development process and baselines established already, then PREFast is a good way to check and enforce those baselines in an objective, repeatable and efficient way.

  • PREFast provides a snapshot at one point in time only. PREFast will give you a snapshot of the security posture of your code base at one point in time. As soon as someone adds or removes code from that code base, those results are obsolete and scans need to be redone. If PREFast or other code scanning tools are included in your code release criteria, make sure you're working off the most accurate and up-to-date data!

With that, happy scanning!



-Kevin

5 comments:

Anonymous said...

You can also use the Windows SDK. I'll post about how you integrate PREFast into Visual Studio 2005 in a later post. Enjoy,

Kevin

nabito said...

Thanks for great article, is it possible to extend the checks using the user defined one?

anyway, I'm still waiting for the next article on PREFast + Windows SDK though.

Kevin Lam (Impacta LLC) said...

Hey Nabito,

Thanks for the comment. I'm not sure how well PREFast can be extended to be honest, now you got me curious ... ;P

Alright thanks again for comment, I'll be blogging again soon!

--Kevin

Neena said...

Good for people to know.

Kevin Lam (Impacta LLC) said...

Thanks Neena. PREFast is one of Microsoft's greatest, yet most hidden secrets, that developers should know about. I am glad you found it useful, thanks!

--Kevin