Using their findings, the team built Nozzle, a run-time tool that takes a two-level approach to detecting heap-spraying attacks.
Nozzle's lightweight emulator scans heap-allocated objects and treats them as though they are code: It disassembles the code, follows the flow, and builds a control-flow graph. This analysis identifies potentially unsafe code within a safe environment. Nozzle also maintains the global heap metric index.
During testing, Nozzle proved its effectiveness by detecting 100 percent of 12 published and 2,000 synthetically constructed heap-spraying exploits. Even with a detection threshold set six times lower than what is required to detect published malicious attacks, Nozzle reported zero false positives when run against 150 popular Internet sites.
But how does Nozzle affect application performance?
"When we designed the algorithms," Livshits says, "given that our primary target for protection is the highly competitive browser market, we had to minimize overhead. If browsers slow down to a crawl when Nozzle is running, the technology just wouldn't be interesting to manufacturers.
"If we examine every single heap object, Nozzle slows down execution by 2 to 14 times. However, by using sampling, we can achieve effective detection and reduce overhead significantly. A sampling rate of 1 in 20 worked for us and incurred only a 5 to 10 percent performance overhead."
Not Just for Browsers
When the researchers started work on the Nozzle project, they had browsers in mind. But when they heard about the PDF exploit earlier this year, they tried an experiment.
"We downloaded the latest copy of Adobe Reader." Zorn recalls. "We instrumented it using Nozzle, and everything worked without any extra effort on our part. We were thrilled, because this suggested that Nozzle is very general and that its techniques can be applied to any attack that uses embedded JavaScript to fill the address space with malicious code objects."
Adds Livshits: "The point is that Nozzle raises the bar considerably for the state of the art in this space. It is the first defensive technology to explicitly go after heap spraying. Plus, there is evidence to show that it can be an effective and reliable general tool." Always a Next Step
Zorn and Livshits would never suggest that Nozzle alone is sufficient protection against heap spraying. Defense in depth is their recommendation, a combination of tactics to counteract memory exploits.
"Nozzle is orthogonal to other defensive strategies," Zorn says. "Defensive programming will always be important, and as more systems support mechanisms such as Data Execution Prevention (DEP), there will be more obstacles to heap exploits."
But doesn't enabling DEP to prevent execution of code within the heap effectively block all instances of heap exploits?
"There are technical and compatibility issues that prevent DEP from being used in some environments," Livshits says. "Plus, we are already hearing of attacks that start by turning off DEP. Also, there have been code-injection-spraying attacks in areas where DEP can't be used. So DEP is not the silver bullet -- and neither is Nozzle."
There is no doubt that once heap-memory exploits are a thing of the past, other threats will appear. Livshits and Zorn relish the challenge, though, because the results of their work are so satisfyingly obvious and demonstrable.
For now, they are interested in those recent code-injection-spraying attacks that foil DEP. They plan to show that Nozzle also can be effective in detecting such attacks -- and that the forces for good can count on another tool to help keep software secure