tag:blogger.com,1999:blog-3835490072282209412026-03-08T00:23:58.385-08:00lcamtuf's old blogUnknown[email protected]Blogger51125tag:blogger.com,1999:blog-383549007228220941.post-45742941778093149472022-10-21T16:15:00.026-07:002024-07-12T12:53:43.227-07:00Officially retiring this...<p></p><div class="separator" style="clear: both; text-align: left;"><img border="0" data-original-height="744" data-original-width="1280" height="186" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhV31oCvMH0BJjdhs0Rfm2hKzZHWcrdnHsW2Br-XCwlnCUJlBIQPXZYM0DTPhJldRTVXQzlB12MGhJ0iiiK_LkbZGsEc2X2xiUp5_Db1rnrJQ_X1FYDk-kLaJxLS5gC3g59rpnrRl50QFf5pEWgfjCedf3NkboPshwl435ORz0vr0eJLRCUga887znrWw/s320/dead_bird_by_angi_shy_d9ilni4-fullview.png" width="320" /></div><span style="font-size: xx-large;">Thank you for stopping by.</span><p></p><p>After more than a decade of posting infosec commentary on this blog, I decided to pull the plug. I still publish quite a bit, but I'm less and less inclined to use<i>&nbsp;blogspot.com</i>. For one, the platform just doesn't seem to be actively maintained; for example, spam issues have gotten so severe that I had to turn off comments a year ago. But I also wanted to write more about other hobbies, and that's difficult when all the subscribers signed up just for the infosec stuff.</p><p>To stay in touch, please <b><a href="https://lcamtuf.substack.com/">subscribe on Substack</a>&nbsp;</b>for weekly long-form articles on a variety of topics. Here's a sampling of my Substack articles you might enjoy:</p><p></p><ul><li><a href="https://lcamtuf.substack.com/p/a-brief-history-of-counting-stuff">The heterodox history of the calculator</a>,</li><li><a href="https://lcamtuf.substack.com/p/random-objects-balls-patent-anti">Anti-garroting innovation in Victorian London</a>,</li><li><a href="https://lcamtuf.substack.com/p/radios-how-do-they-work">Radios, how do they work?</a>,</li><li><a href="https://lcamtuf.substack.com/p/now-youre-thinking-with-relays">Now you're thinking with relays</a>,</li><li><a href="https://lcamtuf.substack.com/p/weekend-projects-getting-silly-with">Getting silly with C</a>.</li></ul><div>Alternatively, you can follow me on <a href="https://twitter.com/lcamtuf"><b>Twitter</b></a> or <b><a href="https://infosec.exchange/@lcamtuf">Mastodon</a></b> for random hot takes.</div>Unknown[email protected]0tag:blogger.com,1999:blog-383549007228220941.post-32523525467602836812021-08-06T18:51:00.006-07:002021-09-29T18:22:13.052-07:00Practical Doomsday<blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;"><p style="text-align: left;"><span style="font-family: inherit;">&nbsp;<a href="https://nostarch.com/practical-doomsday" style="color: #50c0d0; text-align: center;"><img alt="Practical Doomsday" height="538" src="https://lcamtuf.coredump.cx/prep/cover_s.jpg" style="padding-bottom: 1ex; padding-top: 4ex;" width="386" /></a></span></p></blockquote><p style="padding-left: 4ex; padding-right: 4ex;"><b><i>Practical Doomsday</i></b> is an enjoyable, data-packed romp through the world of rational emergency preparedness. It cuts through the noise of 24-hour news to help you zero in on what actually matters: building a diversified rainy-day fund, staying safe online, and dealing with common mishaps ranging from prolonged power outages to wildfires or floods.</p><p style="padding-left: 4ex; padding-right: 4ex; text-align: left;"><span>The goal of the book is not to convince you that the end is nigh. To the contrary: I want to reclaim the concept of prepping from the bunker-dwelling prophets of doom. Disasters are not rare, but emergency preparedness is not about expecting the worst; it's about being able to enjoy our lives to the fullest without worrying about the apocalyptic headline of the day.</span></p><p style="padding-left: 4ex; padding-right: 4ex; text-align: left;"><span>☛&nbsp;</span><a href="https://nostarch.com/download/samples/PracticalDoomsday_SampleCh4.pdf" style="font-family: inherit;" target="_blank"><b>Click here to read a sample chapter</b></a><b><br /></b>☛&nbsp;<b><a href="https://nostarch.com/practical-doomsday" target="_blank">Click to order from the publisher</a></b></p><p style="padding-left: 4ex; padding-right: 4ex; text-align: left;"><span style="font-family: inherit;">Use code </span><span style="color: #3d85c6; font-family: Roboto Mono;">PREORDERDOOMSDAY</span><span style="font-family: inherit;">&nbsp;to get 30% off. <b>Preorders from the publisher get instant early access to a PDF version of the book.</b> Orders can also be placed on</span><span style="font-family: inherit;">&nbsp;</span><a href="https://www.amazon.com/Practical-Doomsday-Sensible-Surviving-Disasters/dp/1718502125/" style="color: #50c0d0; font-family: inherit; text-decoration-line: none;">Amazon</a><span style="font-family: inherit;">,</span><span style="font-family: inherit;">&nbsp;</span><a href="https://www.barnesandnoble.com/w/practical-doomsday-michal-zalewski/1139929176" style="color: #50c0d0; font-family: inherit; text-decoration-line: none;">Barnes &amp; Noble</a><span style="font-family: inherit;">, and in most other places where books are sold.</span></p><p></p>Unknown[email protected]0tag:blogger.com,1999:blog-383549007228220941.post-90540663298071899222017-04-22T15:48:00.000-07:002017-04-22T16:34:05.269-07:00AFL experiments, or please eat your brötli<p> When messing around with <a href='http://lcamtuf.coredump.cx/afl/'>AFL</a>, you sometimes stumble upon something unexpected or amusing. Say, having the fuzzer spontaneously <a href='https://lcamtuf.blogspot.com/2014/11/pulling-jpegs-out-of-thin-air.html'>synthesize JPEG files</a>, <a href='https://lcamtuf.blogspot.com/2014/11/afl-fuzz-nobody-expects-cdata-sections.html'>come up with non-trivial XML syntax</a>, or <a href='https://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html'>discover SQL semantics</a>. </p> <p> It is also fun to challenge yourself to employ fuzzers in non-conventional ways. Two canonical examples are having your fuzzing target call <i>abort()</i> whenever two libraries that are supposed to implement the same algorithm produce different outputs when given identical input data; or when a library produces different outputs when asked to encode or decode the same data several times in a row. </p> <p> Such tricks may sound fanciful, but they actually find interesting bugs. In one case, AFL-based equivalence fuzzing revealed a bunch of fairly rudimentary flaws in <a href='https://groups.google.com/forum/#!topic/afl-users/ypjZu_RW1IU'>common bignum libraries</a>, with some theoretical implications for crypto apps. Another time, output stability checks revealed long-lived issues in <a href='http://seclists.org/fulldisclosure/2013/Nov/83'>IJG jpeg</a> and other widely-used image processing libraries, leaking data across web origins. </p> <p> In one of my recent experiments, I decided to fuzz <a href='https://github.com/google/brotli'><i>brotli</i></a>, an innovative compression library used in Chrome. But since it's been already fuzzed for many CPU-years, I wanted to do it with a twist: stress-test the compression routines, rather than the usually targeted decompression side. The latter is a far more fruitful target for security research, because decompression normally involves dealing with well-formed inputs, whereas compression code is meant to accept arbitrary data and not think about it too hard. That said, the low likelihood of flaws also means that the compression bits are a relatively unexplored surface that may be worth poking with a stick every now and then. </p> <p> In this case, the library held up admirably - spare for a handful of computationally intensive plaintext inputs (that are now easy to spot due to the <a href='https://groups.google.com/forum/#!topic/afl-users/7BoVk_cDpjM'>recent improvements</a> to AFL). But the output corpus synthesized by AFL, after being seeded just with a single file containing just "0", featured quite a few peculiar finds: </p> <ul> <li> <p> Strings that looked like viable bits of HTML or XML: <code>&lt;META HTTP-AAA IDEAAAA</code>, <code>DATA="IIA DATA="IIA DATA="IIADATA="IIA</code>, <code>&lt;/TD></code>. </p> <li> <p> Non-trivial numerical constants: <code>1000,1000,0000000e+000000</code>, <code>0,000 0,000 0,0000 0x600</code>, <code>0000,$000: 0000,$000:00000000000000</code>. </p> <li> <p> Nonsensical but undeniably English sentences: <code>them with them m with them with themselves</code>, <code>in the fix the in the pin th in the tin</code>, <code>amassize the the in the in the inhe@massive in</code>, <code>he the themes where there the where there</code>, <code>size at size at the tie</code>. </p> <li> <p> Bogus but semi-legible URLs: <code>CcCdc.com/.com/m/ /00.com/.com/m/ /00(0(000000CcCdc.com/.com/.com</code> <p> <li> <p> Snippets of Lisp code: <code>))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))</code>. </p> </ul> <p> The results are quite unexpected, given that they are just a product of randomly mutating a single-byte input file and observing the code coverage in a simple compression tool. The explanation is that <i>brotli</i>, in addition to more familiar binary coding methods, uses a static dictionary constructed by analyzing common types of web content. Somehow, by observing the behavior of the program, AFL was able to incrementally reconstruct quite a few of these hardcoded keywords - and then put them together in various semi-interesting ways. Not bad. </p>Unknown[email protected]2tag:blogger.com,1999:blog-383549007228220941.post-88438400800271365762016-08-04T09:23:00.001-07:002016-08-08T19:08:51.398-07:00CSS mix-blend-mode is bad for your browsing history<p> Up until mid-2010, any rogue website could get a good sense of your browsing habits by specifying a distinctive <i>:visited</i> CSS pseudo-class for any links on the page, rendering thousands of interesting URLs off-screen, and then calling the <i>getComputedStyle</i> API to figure out which pages appear in your browser's history. </p> <p> After some deliberation, browser vendors have closed this loophole by disallowing almost all attributes in <i>:visited</i> selectors, spare for the fairly indispensable ability to alter foreground and background colors for such links. The APIs have been also redesigned to prevent the disclosure of this color information via <i>getComputedStyle</i>. </p> <p> This workaround did not fully eliminate the ability to probe your browsing history, but limited it to scenarios where the user can be tricked into unwittingly feeding the style information back to the website one URL at a time. Several fairly convincing attacks have been demonstrated against patched browsers - my own 2013 entry can be found <a href='http://lcamtuf.coredump.cx/yahh/'>here</a> - but they generally depended on the ability to solicit one click or one keypress per every URL tested. In other words, the whole thing did not scale particularly well. </p> <p> Or at least, it wasn't supposed to. In 2014, I described a <a href='http://lcamtuf.coredump.cx/css_calc/'>neat trick</a> that exploited normally imperceptible color quantization errors within the browser, amplified by stacking elements hundreds of times, to implement an <i>n-to-2<sup>n</sup></i> decoder circuit using just the <i>background-color</i> and <i>opacity</i> properties on overlaid <i>&lt;a href=...&gt;</i> elements to easily probe the browsing history of multiple URLs with a single click. To explain the basic principle, imagine wanting to test two links, and dividing the screen into four regions, like so: <ul> <li>Region #1 is lit only when both links are not visited (¬ link_a ∧ ¬ link_b), <li>Region #2 is lit only when link A is not visited but link B is visited (¬ link_a ∧ link_b), <li>Region #3 is lit only when link A is visited but link B is not (link_a ∧ ¬ link_b), <li>Region #4 is lit only when both links are visited (link_a ∧ link_b). </ul> <p> While the page couldn't directly query the visibility of the segments, we just had to convince the user to click the visible segment once to get the browsing history for both links, for example under the guise of dismissing a pop-up ad. (Of course, the attack could be scaled to far more than just 2 URLs.) </p> <p> This problem was eventually addressed by browser vendors by simply improving the accuracy of color quantization when overlaying HTML elements; while this did not eliminate the risk, it made the attack far more computationally intensive, requiring the evil page to stack millions of elements to get practical results. Gave over? Well, not entirely. In the footnote of my 2014 article, I mentioned this: </p> <p style='margin-left: 4ex; color: gray'> "There is an upcoming CSS feature called <a href='https://drafts.fxtf.org/compositing-1/#mix-blend-mode'><i>mix-blend-mode</i></a>, which permits non-linear mixing with operators such as <i>multiply, lighten, darken,</i> and a couple more. These operators make Boolean algebra much simpler and if they ship in their current shape, they will remove the need for all the fun with quantization errors, successive overlays, and such. That said, mix-blend-mode is not available in any browser today." </p> <p> As you might have guessed, patience is a virtue! As of mid-2016, <i>mix-blend-mode</i> - a feature to allow advanced compositing of bitmaps, very similar to the layer blending modes available in photo-editing tools such as Photoshop and GIMP - is shipping in Chrome and Firefox. And as it happens, in addition to their intended purpose, these non-linear blending operators permit us to implement arbitrary Boolean algebra. For example, to implement AND, all we need to do is use <i>multiply</i>: </p> <ul> <li>black (0) x black (0) = black (0) <li>black (0) x white (1) = black (0) <li>white (1) x black (0) = black (0) <li>white (1) x white (1) = white (1) </ul> <p> For a practical demo, <a href='http://lcamtuf.coredump.cx/whack/'>click here</a>. A single click in that whack-a-mole game will reveal the state of 9 visited links to the JavaScript executing on the page. If this was an actual game and if it continued for a bit longer, probing the state of hundreds or thousands of URLs would not be particularly hard to pull off. </p> Unknown[email protected]0tag:blogger.com,1999:blog-383549007228220941.post-28691458250822810362016-05-11T10:15:00.002-07:002016-05-12T15:01:01.161-07:00Clearing up some misconceptions around the "ImageTragick" bug<p> The recent, highly publicized <a href='https://imagetragick.com'>"ImageTragick" vulnerability</a> had countless web developers scrambling to fix a remote code execution vector in ImageMagick - a popular bitmap manipulation tool commonly used to resize, transcode, or annotate user-supplied images on the Web. Whatever your take on "branded" vulnerabilities may be, the flaw certainly is notable for its ease of exploitation: it is an embarrassingly simple shell command injection bug reminiscent of the security weaknesses prevalent in the 1990s, and nearly extinct in core tools today. The issue also bears some parallels to the more far-reaching but equally striking <a href='https://en.wikipedia.org/wiki/Shellshock_(software_bug)'>Shellshock bug</a>. </p> <p> That said, I believe that the publicity that surrounded the flaw was squandered by failing to make one very important point: even with this particular RCE vector fixed, anyone using ImageMagick to process attacker-controlled images is likely putting themselves at a serious risk. </p> <p> The problem is fairly simple: for all its virtues, ImageMagick does not appear to be designed with malicious inputs in mind - and has a <a href='https://twitter.com/OSVDB/status/730447201604788224'>long and colorful history</a> of lesser-known but equally serious security flaws. For a single data point, look no further than the work done several months ago by Jodie Cunningham. Jodie fuzzed IM with a vanilla setup of <a href='http://lcamtuf.coredump.cx/afl/'>afl-fuzz</a> - and quickly identified about two dozen possibly exploitable security holes, along with countless denial of service flaws. A small sample of Jodie's findings can be found <a href='http://www.openwall.com/lists/oss-security/2014/12/24/1'>here</a>. </p> <p> Jodie's efforts probably just scratched the surface; after "ImageTragick", a more recent effort by Hanno Boeck uncovered <a href='https://blog.fuzzing-project.org/45-ImageMagick-heap-overflow-and-out-of-bounds-read.html'>even more bugs</a>; from what I understand, Hanno's work also went only as far as using off-the-shelf fuzzing tools. You can bet that, short of a major push to redesign the entire IM codebase, the trickle won't stop any time soon. </p> <p> And so, the advice sorely missing from the "ImageTragick" webpage is this: </p> <p> <ul> <li> <p> If all you need to do is simple transcoding or thumbnailing of potentially untrusted images, don't use ImageMagick. Make a direct use of libpng, libjpeg-turbo, and giflib; for a robust way to use these libraries, have a look at the source code of Chromium or Firefox. The resulting implementation will be considerably faster, too. </p> <li> <p> If you <i>have to</i> use ImageMagick on untrusted inputs, consider sandboxing the code with <i>seccomp-bpf</i> or an equivalent mechanism that robustly restricts access to all user space artifacts and to the kernel attack surface. Rudimentary sandboxing technologies, such as <i>chroot()</i> or UID separation, are probably not enough. </p> <li> <p> If all other options fail, be zealous about limiting the set of image formats you actually pass down to IM. The bare minimum is to thoroughly examine the headers of the received files. It is also helpful to explicitly specify the input format when calling the utility, as to preempt auto-detection code. For command-line invocations, this can be done like so: </p> <p> <code>convert [...other params...] -- jpg:input-file.jpg jpg:output-file.jpg</code> </p> <p> The JPEG, PNG, and GIF handling code in ImageMagick is considerably more robust than the code that supports PCX, TGA, SVG, PSD, and the likes. </p> </ul> Unknown[email protected]4tag:blogger.com,1999:blog-383549007228220941.post-27533971796782524452016-02-09T12:45:00.000-08:002016-02-12T12:23:55.544-08:00Automatically inferring file syntax with afl-analyze<p> The nice thing about the <a href='http://lcamtuf.coredump.cx/afl/technical_details.txt'>control flow instrumentation</a> used by <a href='http://lcamtuf.coredump.cx/afl/'>American Fuzzy Lop</a> is that it allows you to do much more than just, well, fuzzing stuff. For example, the suite has long shipped with a standalone tool called <i>afl-tmin</i>, capable of automatically shrinking test cases while still making sure that they exercise the same functionality in the targeted binary (or that they trigger the same crash). Another similar tool, <i>afl-cmin</i>, employed a similar trick to eliminate redundant files in any large testing corpora. </p> <p> The latest release of AFL features another nifty new addition along these lines: <i>afl-analyze</i>. The tool takes an input file, sequentially flips bytes in this data stream, and then observes the behavior of the targeted binary after every flip. From this information, it can infer several things: </p> <ul> <li> Classify some content as no-op blocks that do not elicit any changes to control flow (say, comments, pixel data, etc). <li> Checksums, magic values, and other short, atomically compared tokens where any bit flip causes the same change to program execution. <li> Longer blobs exhibiting this property - almost certainly corresponding to checksummed or encrypted data. <li> "Pure" data sections, where analyzer-injected changes consistently elicit differing changes to control flow. </ul> <p> This gives us some remarkable and quick insights into the syntax of the file and the behavior of the underlying parser. It may sound too good to be true, but actually seems to work in practice. For a quick demo, let's see what <i>afl-analyze</i> has to say about running <i>cut -d ' ' -f1</i> on a text file: </p> <p> <img src='http://lcamtuf.coredump.cx/afl/analyze-cut.png' width=675 height=290 style='border: 1px solid teal; margin-left: 4ex'> </p> <p> We see that <i>cut</i> really only cares about spaces and newlines. Interestingly, it also appears that the tool always tokenizes the entire line, even if it's just asked to return the first token. Neat, right? </p> <p> Of course, the value of <i>afl-analyze</i> is greater for incomprehensible binary formats than for simple text utilities; perhaps even more so when dealing with black-box parsers (which can be analyzed thanks to the runtime QEMU instrumentation supported in AFL). To try out the tool's ability to deal with binaries, let's check out <i>libpng</i>: </p> <p> <img src='http://lcamtuf.coredump.cx/afl/analyze-readpng.png' width=795 height=263 style='border: 1px solid teal; margin-left: 4ex'> </p> <p> This looks pretty damn good: we have two four-byte signatures, followed by chunk length, four-byte chunk name, chunk length, some image metadata, and then a comment section. Neat, right? All in a matter of seconds: no configuration needed and no knobs to turn. </p> <p> Of course, the tool shipped just moments ago and is still very much experimental; expect some kinks. Field testing and feedback welcome! </p>Unknown[email protected]4tag:blogger.com,1999:blog-383549007228220941.post-91036456282414975322015-06-11T15:15:00.001-07:002015-08-31T16:38:32.171-07:00New in AFL: persistent mode<p> Although <a href='http://lcamtuf.coredump.cx/afl/'>American Fuzzy Lop</a> comes with a couple of nifty performance optimizations, it still relies on a fairly resource-intensive routine that is common to most general-purpose fuzzers: it continually creates new processes, feeds them a single test case, and then discards them to start over from scratch. </p> <p> To avoid the overhead of the notoriously slow <i>execve()</i> syscall and the linking process, the fuzzer automatically leverages the <a href='http://lcamtuf.blogspot.com/2014/10/fuzzing-binaries-without-execve.html'>forkserver optimization</a>, where new processes are cloned from a copy-on-write master perpetually kept in a virgin state. This allows many targets to be fuzzed faster than with other, conventional tools. But even with this hack, each new input still incurs the cost of <i>fork()</i>. On all supported OSes with the exception of MacOS X, the <i>fork()</i> call is actually surprisingly fast - but certainly does not come free. </p> <p> For some common fuzzing targets, such as <i>zlib</i> or <i>libpng</i>, the constant cycle of forking and initialization is a significant and avoidable bottleneck. In many cases, the underlying APIs are either stateless, or can be reliably reset to a nearly-pristine state across inputs - so at least in principle, you don't have to throw away the child process after every single run. That's where in-process fuzzing tends to shine: in this scheme, the test cases are generated inline and fed to the underlying API in a custom-written, single-process loop. The speed gains offered by in-process fuzzing can be as high as 10x, but the approach comes at a price; for example, it is easily derailed by accidental memory leaks or DoS conditions in the tested code. </p> <p> Well, the good news is that starting with version 1.81b, <i>afl-fuzz</i> supports an optional "persistent" mode that combines the benefits of in-process fuzzing with the robustness of a more traditional multi-process tool. In this scheme, the fuzzer feeds test cases to a separate, long-lived process that reads the input data, passes it to the instrumented API, notifies the parent about successful run by stopping its own execution; eventually, when resumed by the parent, the process simply loops back to the start. You just need to write a minimalist harness to implement the loop, but AFL takes care of most of the tricky stuff, including crash handling, stall detection, and the usual instrumentation magic that AFL is designed for: </p> <pre> int main(int argc, char** argv) { while (__AFL_LOOP(1000)) { /* Reset state. */ memset(buf, 0, 100); /* Read input data. */ read(0, buf, 100); /* Parse it in some vulnerable way. You'd normally call a library here. */ if (buf[0] != 'p') puts("error 1"); else if (buf[1] != 'w') puts("error 2"); else if (buf[2] != 'n') puts("error 3"); else abort(); } } </pre> <p> For a more complete example, see <i>experimental/persistent_demo/</i> and be sure to read the last section of <i>llvm_mode/README.llvm</i>. This feature is inspired by the work done by Kostya Serebryany on <a href='http://llvm.org/docs/LibFuzzer.html'>LibFuzzer</a> (which is, in turn, inspired by AFL); additional credit goes to Christian Holler, who started a conversation that finally prompted me to integrate this mode with the tool. </p> Unknown[email protected]0tag:blogger.com,1999:blog-383549007228220941.post-7192983631124369962015-04-14T11:32:00.000-07:002015-04-14T15:34:55.005-07:00Finding bugs in SQLite, the easy way<a href='https://sqlite.org/'>SQLite</a> is probably the most popular embedded database in use today; it is also known for being <a href='https://www.sqlite.org/testing.html'>exceptionally well-tested</a> and robust. In contrast to traditional SQL solutions, it does not rely on the usual network-based client-server architecture and does not employ a complex ACL model; this simplicity makes it comparatively safe. <p></p> At the same time, because of its versatility, SQLite sometimes finds use as the mechanism behind SQL-style query APIs that are exposed between privileged execution contexts and less-trusted code. For an example, look no further than the <a href='http://slides.html5rocks.com/#web-sql-db'>WebDB / WebSQL</a> mechanism available in some browsers; in this setting, any vulnerabilities in the SQLite parser can open up the platform to attacks. <p></p> With this in mind, I decided to take SQLite for a spin with - you guessed it - <a href='http://lcamtuf.coredump.cx/afl/'>afl-fuzz</a>. As discussed some time ago, languages such as SQL tend to be difficult to stress-test in a fully automated manner: without an intricate model of the underlying grammar, random mutations are unlikely to generate anything but trivially broken statements. That said, <i>afl-fuzz</i> can usually leverage the injected instrumentation to sort out the grammar on its own. All I needed to get it started is a basic dictionary; for that, I took about 5 minutes to extract a list of reserved keywords from the SQLite docs (now included with the fuzzer as <i>testcases/_extras/sql/</i>). Next, I seeded the fuzzer with a single test case: <p></p> <pre> create table t1(one smallint); insert into t1 values(1); select * from t1;</pre> <p></p> This approach netted a decent number of interesting finds, some of which were mentioned in an <a href='http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html'>earlier blog post</a> that first introduced the dictionary feature. But when looking at the upstream fixes for the initial batch, I had a sudden moment of clarity and recalled that the developers of SQLite maintained a remarkably well-structured and comprehensive suite of hand-written test cases in their repository. <p></p> I figured that this body of working SQL statements may be a much better foundation for the fuzzer to build on, compared to my naive query - so I grepped the test cases out, split them into files, culled the resulting corpus with <i>afl-cmin</i>, and trimmed the inputs with <i>afl-tmin</i>. After a short while, I had around 550 files, averaging around 220 bytes each. I used them as a starting point for another run of <i>afl-fuzz</i>. <p></p> This configuration very quickly yielded a fair number of additional, unique fault conditions, ranging from NULL pointer dereferences, to memory fenceposts visible only under ASAN or Valgrind, to pretty straightforward uses of uninitialized pointers (<a href='https://www.sqlite.org/src/info/eddc05e7bb31fae7'>link</a>), bogus calls to <i>free()</i> (<a href='https://www.sqlite.org/src/info/02e3c88fbf6abdcf'>link</a>), heap buffer overflows (<a href='https://www.sqlite.org/src/info/586a94e85bc13700'>link</a>), and even stack-based ones (<a href='https://www.sqlite.org/src/info/c494171f77dc2e5e'>link</a>). The resulting collection of 22 crashing test cases is included with the fuzzer in <i>docs/vuln_samples/sqlite_*</i>. They include some fairly ornate minimized inputs, say: <p></p> <code>CREATE VIRTUAL TABLE t0 USING fts4(x,order=DESC);<br> INSERT INTO t0(docid,x)VALUES(-1E0,'0(o');<br> INSERT INTO t0 VALUES('');<br> INSERT INTO t0 VALUES('');<br> INSeRT INTO t0 VALUES('o');<br> SELECT docid FROM t0 WHERE t0 MATCH'"0*o"';</code> <p></p> All in all, it's a pretty good return on investment for about 30 minutes of actual work - especially for a piece of software functionally tested and <a href='https://www.sqlite.org/testing.html'>previously fuzzed</a> to such a significant extent. <p></p> PS. I was truly impressed with Richard Hipp fixing each and every of these cases within a couple of hours of sending in a report. The fixes have been incorporated in version 3.8.9 of SQLite and have been public for a while, but there was no upstream advisory; depending on your use case, you may want to update soon.Unknown[email protected]6tag:blogger.com,1999:blog-383549007228220941.post-12085219488319073622015-03-30T02:42:00.001-07:002021-09-08T17:49:42.869-07:00On journeys<div style='font-family: Georgia, Arial, Helvetica; line-height: 1.8; font-size: 110%'> <p><b>- 1 -</b></p> <p> Poland is an ancient country whose history is deeply intertwined with that of the western civilization. In its glory days, the Polish-Lithuanian Commonwealth sprawled across vast expanses of land in central Europe, from Black Sea to Baltic Sea. But over the past two centuries, it suffered a series of military defeats and political partitions at the hands of its closest neighbors: Russia, Austria, Prussia, and - later - Germany. </p> <p> After more than a hundred years of foreign rule, Poland re-emerged as an independent state in 1918, only to face the armies of Nazi Germany at the onset of World War II. With Poland's European allies reneging on their earlier military guarantees, the fierce fighting left the country in ruins. Some six million people have died within its borders - more than ten times the death toll in France or in the UK. Warsaw was reduced to a sea of rubble, with perhaps one in ten buildings still standing by the end of the war. </p> <p> With the collapse of the Third Reich, Franklin D. Roosevelt, Winston Churchill, and Joseph Stalin held a meeting in Yalta to decide the new order for war-torn Europe. At Stalin's behest, Poland and its neighboring countries were placed under Soviet political and military control, forming what has become known as the Eastern Bloc. </p> <p> Over the next several decades, the Soviet satellite states experienced widespread repression and economic decline. But weakened by the expense of the Cold War, the communist chokehold on the region eventually began to wane. In Poland, even the introduction of martial law in 1981 could not put an end to sweeping labor unrest. Narrowly dodging the specter of Soviet intervention, the country regained its independence in 1989 and elected its first democratic government; many other Eastern Bloc countries soon followed suit. </p> <p> Ever since then, Poland has enjoyed a period of unprecedented growth and has emerged as one of the more robust capitalist democracies in the region. In just two decades, it shed many of its backwardly, state-run heavy industries and adopted a modern, service-oriented economy. But the effects of the devastating war and the lost decades under communist rule still linger on - whether you look at the country's infrastructure, at its socrealist cityscapes, at its political traditions, or at the depressingly low median wage. </p> <p> When thinking about the American involvement in the Cold War, people around the world may recall Vietnam, Bay of Pigs, or the proxy wars fought in the Middle East. But in Poland and many of its neighboring states, the picture you remember the most is the fall of the Berlin Wall. </p> <p><b>- 2 -</b></p> <p> I was born in Warsaw in the winter of 1981, at the onset of martial law, with armored vehicles rolling onto Polish streets. My mother, like many of her generation, moved to the capital in the sixties as a part of an effort to rebuild and repopulate the war-torn city. My grandma would tell eerie stories of Germans and Soviets marching through their home village somewhere in the west. I liked listening to the stories; almost every family in Poland had some to tell. </p> <p> I did not get to know my father. I knew his name; he was a noted cinematographer who worked on big-ticket productions back in the day. He left my mother when I was very young and never showed interest in staying in touch. He had a wife and other children, so it might have been that. </p> <p> Compared to him, mom hasn't done well for herself. We ended up in social housing in one of the worst parts of the city, on the right bank of the Vistula river. My early memories from school are that of classmates sniffing glue from crumpled grocery bags. I remember my family waiting in lines for rationed toilet paper and meat. As a kid, you don't think about it much. </p> <p> The fall of communism came suddenly. I have a memory of grandma listening to broadcasts from Radio Free Europe, but I did not understand what they were all about. I remember my family cheering one afternoon, transfixed to a black-and-white TV screen. I recall my Russian language class morphing into English; I had my first taste of bananas and grapefruits. There is the image of the monument of Feliks Dzierżyński coming down. I remember being able to go to a better school on the other side of Warsaw - and getting mugged many times on the way. </p> <p> The transformation brought great wealth to some, but many others have struggled to find their place in the fledgling and sometimes ruthless capitalist economy. Well-educated and well read, my mom ended up in the latter pack, at times barely making ends meet. I think she was in part a victim of circumstance, and in part a slave to way of thinking that did not permit the possibility of taking chances or pursuing happiness. </p> <p><b>- 3 -</b></p> <p> Mother always frowned upon popular culture, seeing it as unworthy of an educated mind. For a time, she insisted that I only listen to classical music. She angrily shunned video games, comic books, and cartoons. I think she perceived technology as trivia; the only field of science she held in high regard was abstract mathematics, perhaps for its detachment from the mundane world. She hoped that I would learn Latin, a language she could read and write; that I would practice drawing and painting; or that I would read more of the classics of modernist literature. </p> <p> Of course, I did almost none of that. I hid my grunge rock tapes between Tchaikovsky, listened to the radio under the sheets, and watched the reruns of <i>The A-Team</i> while waiting for her to come back from work. I liked electronics and chemistry a lot more than math. And when I laid my hands on my first computer - an 8-bit relic of British engineering from 1982 - I soon knew that these machines, in their incredible complexity and flexibility, were what I wanted to spend my time on. </p> <p> I suspected I could become a competent programmer, but never had enough faith in my skill. Yet, in learning about computers, I realized that I had a knack for understanding complex systems and poking holes in how they work. With a couple of friends, we joined the nascent information security community in Europe, comparing notes on mailing lists. Before long, we were taking on serious consulting projects for banks and the government - usually on weekends and after school, but sometimes skipping a class or two. Well, sometimes more than that. </p> <p> All of the sudden, I was facing an odd choice. I could stop, stay in school and try to get a degree - going back every night to a cramped apartment, my mom sleeping on a folding bed in the kitchen, my personal space limited to a bare futon and a tiny desk. Or, I could seize the moment and try to make it on my own, without hoping that one day, my family would be able to give me a head start. </p> <p> I moved out, dropped out of school, and took on a full-time job. It paid somewhere around $12,000 a year - a pittance anywhere west of the border, but a solid wage in Poland even today. Not much later, I was making two times as much, about the upper end of what one could hope for in this line of work. I promised myself to keep taking courses after hours, but I wasn't good at sticking to the plan. I moved in with my girlfriend, and at the age of 19, I felt for the first time that things were going to be all right. </p> <p><b>- 4 -</b></p> <p> Growing up in Europe, you get used to the barrage of low-brow swipes taken at the United States. Your local news will never pass up the opportunity to snicker about the advances of creationism somewhere in Kentucky. You can stay tuned for a panel of experts telling you about the vastly inferior schools, the medieval justice system, and the striking social inequality on the other side of the pond. You don't doubt their words - but deep down inside, no matter how smug the critics are, or how seemingly convincing their arguments, the American culture still draws you in. </p> <p> My moment of truth came in the summer of 2000. A company from Boston asked me if I'd like to talk about a position on their research team; I looked at the five-digit figure and could not believe my luck. Moving to the US was an unreasonable risk for a kid who could barely speak English and had no safety net to fall back to. But that did not matter: I knew I had no prospects of financial independence in Poland - and besides, I simply needed to experience the New World through my own eyes. </p> <p> Of course, even with a job offer in hand, getting into the United States is not an easy task. An engineering degree and a willing employer opens up a straightforward path; it is simple enough that some companies would abuse the process to source cheap labor for menial, low-level jobs. With a visa tied to the petitioning company, such captive employees could not seek better wages or more rewarding work. </p> <p> But without a degree, the options shrink drastically. For me, the only route would be a seldom-granted visa reserved for extraordinary skill - meant for the recipients of the Nobel Prize and other folks who truly stand out in their field of expertise. The attorneys looked over my publication record, citations, and the supporting letters from other well-known people in the field. Especially given my age, they thought we had a good shot. A few stressful months later, it turned out that they were right. </p> <p> On the week of my twentieth birthday, I packed two suitcases and boarded a plane to Boston. My girlfriend joined me, miraculously securing a scholarship at a local university to continue her physics degree; her father helped her with some of the costs. We had no idea what we were doing; we had perhaps few hundred bucks on us, enough to get us through the first couple of days. Four thousand miles away from our place of birth, we were starting a brand new life. </p> <p><b>- 5 -</b></p> <p> The cultural shock gets you, but not in the sense you imagine. You expect big contrasts, a single eye-opening day to remember for the rest of your life. But driving down a highway in the middle of a New England winter, I couldn't believe how ordinary the world looked: just trees, boxy buildings, and pavements blanketed with dirty snow. </p> <p> Instead of a moment of awe, you drown in a sea of small, inconsequential things, draining your energy and making you feel helpless and lost. It's how you turn on the shower; it's where you can find a grocery store; it's what they meant by that incessant "paper or plastic" question at the checkout line. It's how you get a mailbox key, how you make international calls, it's how you pay your bills with a check. It's the rules at the roundabout, it's your social security number, it's picking the right toll lane, it's getting your laundry done. It's setting up a dial-up account and finding the food you like in the sea of unfamiliar brands. It's doing all this without Google Maps or a Facebook group to connect with other expats nearby. </p> <p> The other thing you don't expect is losing touch with your old friends; you can call or e-mail them every day, but your social frames of reference begin to drift apart, leaving less and less to talk about. The acquaintances you make in the office will probably never replace the folks you grew up with. We managed, but we weren't prepared for that. </p> <p><b>- 6 -</b></p> <p> In the summer, we had friends from Poland staying over for a couple of weeks. By the end of their trip, they asked to visit New York City one more time; we liked the Big Apple, so we took them on a familiar ride down I-95. One of them went to see the top of World Trade Center; the rest of us just walked around, grabbing something to eat before we all headed back. A few days later, we were all standing in front of a TV, watching September 11 unfold in real time. </p> <p> We felt horror and outrage. But when we roamed the unsettlingly quiet streets of Boston, greeted by flags and cardboard signs urging American drivers to honk, we understood that we were strangers a long way from home - and that our future in this country hanged in the balance more than we would have thought. </p> <p> Permanent residency is a status that gives a foreigner the right to live in the US and do almost anything they please - change jobs, start a business, or live off one's savings all the same. For many immigrants, the pursuit of this privilege can take a decade or more; for some others, it stays forever out of reach, forcing them to abandon the country in a matter of days as their visas expire or companies fold. With my O-1 visa, I always counted myself among the lucky ones. Sure, it tied me to an employer, but I figured that sorting it out wouldn't be a big deal. </p> <p> That proved to be a mistake. In the wake of 9/11, an agency known as Immigration and Naturalization Services was being dismantled and replaced by a division within the Department of Homeland Security. My own seemingly straightforward immigration petition ended up somewhere in the bureaucratic vacuum that formed in between the two administrative bodies. I waited patiently, watching the deepening market slump, and seeing my employer's prospects get dimmer and dimmer every month. I was ready for the inevitable, with other offers in hand, prepared to make my move perhaps the very first moment I could. But the paperwork just would not come through. With the Boston office finally shutting down, we packed our bags and booked flights. We faced the painful admission that for three years, we chased nothing but a pipe dream. The only thing we had to show for it were two adopted cats, now sitting frightened somewhere in the cargo hold. </p> <p> The now-worthless approval came through two months later; the lawyers, cheerful as ever, were happy to send me a scan. The hollowed-out remnants of my former employer were eventually bought by Symantec - the very place from where I had my backup offer in hand. </p> <p><b>- 7 -</b></p> <p> In a way, Europe's obsession with America's flaws made it easier to come home without ever explaining how the adventure really played out. When asked, I could just wing it: a mention of the death penalty or permissive gun laws would always get you a knowing nod, allowing the conversation to move on. </p> <p> Playing to other people's preconceptions takes little effort; lying to yourself calls for more skill. It doesn't help that when you come back after three years away from home, you notice all the small annoyances that you used to simply tune out. Back then, Warsaw still had a run-down vibe: the dilapidated road from the airport; the drab buildings on the other side of the river; the uneven pavements littered with dog poop; the dirty walls at my mother's place, with barely any space to turn. You can live with it, of course - but it's a reminder that you settled for less, and it's a sensation that follows you every step of the way. </p> <p> But more than the sights, I couldn't forgive myself something else: that I was coming back home with just loose change in my pocket. There are some things that a failed communist state won't teach you, and personal finance is one of them; I always looked at money just as a reward for work, something you get to spend to brighten your day. The indulgences were never extravagant: perhaps I would take the cab more often, or have take-out every day. But no matter how much I made, I kept living paycheck-to-paycheck - the only way I knew, the way our family always did. </p> <p><b>- 8 -</b></p> <p> With a three-year stint in the US on your resume, you don't have a hard time finding a job in Poland. You face the music in a different way. I ended up with a salary around a fourth of what I used to make in Massachusetts; I simply decided not to think about it much. I wanted to settle down, work on interesting projects, marry my girlfriend, have a child. I started doing consulting work whenever I could, setting almost all the proceeds aside. </p> <p> After four years with T-Mobile in Poland, I had enough saved to get us through a year or so - and in a way, it changed the way I looked at my work. Being able to take on ambitious challenges and learn new things started to matter more than jumping ships for a modest salary bump. Burned by the folly of pursuing riches in a foreign land, I put a premium on boring professional growth. </p> <p> Comically, all this introspection made me realize that from where I stood, I had almost nowhere left to go. Sure, Poland had telcos, refineries, banks - but they all consumed the technologies developed elsewhere, shipped here in a shrink-wrapped box; as far as their IT went, you could hardly tell the companies apart. To be a part of the cutting edge, you had to pack your bags, book a flight, and take a jump into the unknown. I sure as heck wasn't ready for that again. </p> <p> And then, out of the blue, Google swooped in with an offer to work for them from the comfort of my home, dialing in for a videoconference every now and then. The starting pay was about the same as what I was making at a telco, but I had no second thoughts. I didn't say it out loud, but deep down inside, I already knew what needed to happen next. </p> <p><b>- 9 -</b></p> <p> We moved back to the US in 2009, two years after taking the job, already on the hook for a good chunk of Google's product security and with the comfort of knowing where we stood. In a sense, my motive was petty: you could call it a desire to vindicate a failed adolescent dream. But in many other ways, I have grown fond of the country that shunned us once before; and I wanted our children to grow up without ever having to face the tough choices and the uncertain prospects I had to deal with in my earlier years. </p> <p> This time, we knew exactly what to do: a quick stop at a grocery store on a way from the airport, followed by e-mail to our immigration folks to get the green card paperwork out the door. A bit more than half a decade later, we were standing in a theater in Campbell, reciting the Oath of Allegiance and clinging on to our new certificates of US citizenship. </p> <p> The ceremony closed a long and interesting chapter in my life. But more importantly, standing in that hall with people from all over the globe made me realize that my story is not extraordinary; many of them had lived through experiences far more harrowing and captivating than mine. If anything, my tale is hard to tell apart from that of countless other immigrants from the former Eastern Bloc. By some estimates, in the US alone, the Polish diaspora is about 9 million strong. </p> <p> I know that the Poland of today is not the Poland I grew up in. It's not not even the Poland I came back to in 2003; the gap to Western Europe is shrinking every single year. But I am grateful to now live in a country that welcomes more immigrants than any other place on Earth - and at the end of their journey, makes many of them them feel at home. It also makes me realize how small and misguided are the conversations we are having about immigration - on both sides of the aisle, and not just here, but all over the developed world. </p> </div> Unknown[email protected]23tag:blogger.com,1999:blog-383549007228220941.post-58399740269507031272015-03-11T00:38:00.000-07:002015-03-11T00:42:56.540-07:00Another round of image bugs: PNG and JPEG XRToday's release of <a href='https://technet.microsoft.com/library/security/MS15-024'>MS15-024</a> and <a href='https://technet.microsoft.com/library/security/MS15-029'>MS15-029</a> addresses two more <a href='http://lcamtuf.blogspot.com/2015/02/bi-level-tiffs-and-tale-of-unexpectedly.html'>image-related memory disclosure vulnerabilities</a> in Internet Explorer - this time, affecting the little-known JPEG XR format supported by this browser, plus the far more familiar PNG. Similarly to the previously discussed bugs in MSIE TIFF and JPEG parsing, and to the BMP, ICO, and GIF and JPEG DHT & SOS flaws in Firefox and Chrome, these two were found with <a href='http://lcamtuf.coredump.cx/afl/'>afl-fuzz</a>. The earlier posts have more context - today, just enjoy some pretty pics, showing subsequent renderings of the same JPEG XR image: <p> <img src='http://lcamtuf.coredump.cx/afl/jxr_demo.png' width=521 height=66> <p> Proof-of-concepts are <a href='http://lcamtuf.coredump.cx/iejxr/'>here</a> (JXR) and <a href='http://lcamtuf.coredump.cx/iepng/'>here</a> (PNG). I am happy to report that Microsoft fixed them within roughly three months of the original report. <p> The total number of bugs squashed in this category is now ten. I have just one more multi-browser image parsing bug outstanding - but it should be an interesting one. Stay tuned.Unknown[email protected]2tag:blogger.com,1999:blog-383549007228220941.post-44711281079219423402015-02-10T10:55:00.000-08:002015-02-12T16:35:37.855-08:00Bi-level TIFFs and the tale of the unexpectedly early patchToday's release of <a href='https://technet.microsoft.com/library/security/MS15-016'>MS15-016</a> (CVE-2015-0061) fixes another of the series of browser memory disclosure bugs found with <a href='http://lcamtuf.coredump.cx/afl/'>afl-fuzz</a> - this time, related to the handling of bi-level (1-bpp) TIFFs in Internet Explorer (yup, MSIE displays TIFFs!). You can check out a simple proof-of-concept <a href='http://lcamtuf.coredump.cx/ietiff/'>here</a>, or simply enjoy this screenshot of eight subsequent renderings of the same TIFF file: <p> <img src='http://lcamtuf.coredump.cx/ietiff/ietiff.jpg' width=530 height=68> </p> The vulnerability is conceptually similar to other previously-identified problems with GIF and JPEG handling in popular browsers (<a href='http://lcamtuf.blogspot.com/2014/10/two-more-browser-memory-disclosure-bugs.html'>example 1</a>, <a href='http://lcamtuf.blogspot.com/2014/09/cve-2014-1564-uninitialized-memory-when.html'>example 2</a>), with the SOS handling bug in <i>libjpeg</i>, or the DHT bug in <i>libjpeg-turbo</i> (<a href='http://seclists.org/fulldisclosure/2013/Nov/83'>details here</a>) - so I will try not to repeat the same points in this post. <p></p> Instead, I wanted to take note of what really sets this bug apart: Microsoft has addressed it in precisely 60 days, counting form my initial e-mail to the availability of a patch! This struck me as a big deal: although vulnerability research is not my full-time job, I do have a decent sample size - and I don't think I have seen this happen for any of the few dozen MSIE bugs that I reported to MSRC over the past few years. The average patch time always seemed to be closer to 6+ months - coupled with what the somewhat odd practice of withholding attribution in security bulletins and engaging in seemingly punitive PR outreach if the reporter ever went public before that. <p></p> I am very excited and hopeful that rapid patching is the new norm - and huge thanks to MSRC folks if so :-)Unknown[email protected]0tag:blogger.com,1999:blog-383549007228220941.post-46038685533191468522015-01-09T19:22:00.000-08:002015-01-09T22:15:31.381-08:00afl-fuzz: making up grammar with a dictionary in handOne of the most significant limitations of <a href='http://lcamtuf.coredump.cx/afl/'>afl-fuzz</a> is that its mutation engine is syntax-blind and optimized for compact data formats, such as binary files (e.g., archives, multimedia) or terse human-readable languages (RTF, shell scripts). Any general-purpose fuzzer will have a harder time dealing with more verbose dialects, such as SQL or HTTP. You can improve your odds in a variety of ways, and the results can be <a href='http://lists.cs.uiuc.edu/pipermail/llvmdev/2014-December/079421.html'>surprisingly good</a> - but ultimately, it's never easy to get from <i>Set-Cookie: FOO=BAR</i> to <i>Content-Length: -1</i> by randomly flipping bits. <p></p> The common wisdom is that if you want to fuzz data formats with such ornate grammars, you need to build an one-off, protocol-specific mutation engine with the appropriate syntax templates baked in. Of course, writing such code isn't easy. In essence, you need to manually build a model precise enough so that the generated test cases almost always make sense to the targeted parser - but creative enough to trigger unintended behaviors in that codebase. It takes considerable experience and a fair amount of time to get it just right. <p></p> I was thinking about using <i>afl-fuzz</i> to reach some middle ground between the two worlds. I quickly realized that if you give the fuzzer a list of basic syntax tokens - say, the set of reserved keywords defined in the spec - the instrumentation-guided nature of the tool means that even if we just mindlessly clobber the tokens together, we will be able to distinguish between combinations that are nonsensical and ones that actually follow the rules of the underlying grammar and therefore trigger new states in the instrumented binary. By discarding that first class of inputs and refining the other, we could progressively construct more complex and meaningful syntax as we go. <p></p> Ideas are cheap, but when I implemented this one, it turned out to be a good bet. For example, I tried it against <i>sqlite</i>, with the fuzzer fed a collection of keywords grabbed from the project's docs (<i>-x testcases/_extras/sql/</i>). Equipped with this knowledge, <i>afl-fuzz</i> quickly spewed out a range of <u>valid</u> if unusual statements, such as: <p></p> <xmp>select sum(1)LIMIT(select sum(1)LIMIT -1,1); select round( -1)````; select group_concat(DISTINCT+1) |1; select length(?)in( hex(1)+++1,1); select abs(+0+ hex(1)-NOT+1) t1; select DISTINCT "Y","b",(1)"Y","b",(1); select - (1)AND"a","b"; select ?1in(CURRENT_DATE,1,1); select - "a"LIMIT- /* */ /* */- /* */ /* */-1; select strftime(1, sqlite_source_id());</xmp> <p></p> (It also found a couple of <a href='https://www.mail-archive.com/[email protected]/msg88058.html'>crashing bugs</a>.) <p></p> All right, all right: grabbing keywords is much easier than specifying the underlying grammar, but it still takes some work. I've been wondering how to scratch that itch, too - and came up with a fairly simple algorithm that can help those who do not have the time or the inclination to construct a proper dictionary. <p></p> To explain the approach, it's useful to rely on the example of a PNG file. The PNG format uses four-byte, human-readable magic values to indicate the beginning of a section, say: <p></p> <code>89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 | .PNG........<span style='color: crimson'>IHDR</span><br> 00 00 00 20 00 00 00 20 02 03 00 00 00 0e 14 92 | ................ </code> <p></p> The algorithm in question can identify "IHDR" as a syntax token by piggybacking on top of the deterministic, sequential bit flips that are already being performed by <i>afl-fuzz</i> across the entire file. It works by identifying runs of bytes that satisfy a simple property: that flipping them triggers an execution path that is distinct from the product of flipping stuff in the neighboring regions, yet consistent across the entire sequence of bytes. <p></p> This signal strongly implies that touching any of the affected bytes causes the failure of an underlying atomic check, such as <i>header.magic_value == 0xDEADBEEF</i> or <i>strcmp(name, "Set-Cookie")</i>. When such a behavior is detected, the entire blob of data is added to the dictionary, to be randomly recombined with other dictionary tokens later on. <p></p> This second trick is not a substitute for a proper, hand-crafted list of keywords; for one, it will only know about the syntax tokens that were present in the input files, or could be synthesized easily. It will also not do much when pitted against optimized, tree-based parsers that do not perform atomic string comparisons. (The fuzzer itself can often <a href='http://lcamtuf.blogspot.com/2014/11/afl-fuzz-nobody-expects-cdata-sections.html'>clear that last obstacle</a> anyway, but the process will be slow.) <p></p> Well, that's it. If you want to try out the new features, <a href='http://lcamtuf.coredump.cx/afl/'>click here</a> and let me know how it goes!Unknown[email protected]6tag:blogger.com,1999:blog-383549007228220941.post-22946844335472856372014-11-30T13:39:00.000-08:002015-01-09T22:19:51.669-08:00afl-fuzz: nobody expects CDATA sections in XMLI made a very explicit, pragmatic <a href='http://lcamtuf.coredump.cx/afl/related_work.txt'>design decision</a> with <a href='http://lcamtuf.coredump.cx/afl/'>afl-fuzz</a>: for performance and reliability reasons, I did not want to get into static analysis or symbolic execution to understand what the program is actually doing with the data we are feeding to it. The basic algorithm for the fuzzer can be just summed up as randomly mutating the input files, and gently nudging the process toward new state transitions discovered in the targeted binary. That discovery part is done with the help of lightweight and extremely simple instrumentation injected by the compiler. <p></p> I had a working theory that this would make the fuzzer a bit smarter than a potato, but I wasn't expecting any fireworks. So, when the algorithm managed to not only find some useful real-world bugs, but to <a href='http://lcamtuf.blogspot.com/2014/11/pulling-jpegs-out-of-thin-air.html'>successfully synthesize a JPEG file</a> out of nothing, I was genuinely surprised by the outcome. <p></p> Of course, while it was an interesting result, it wasn't an impossible one. In the end, the fuzzer simply managed to wiggle its way through a long and winding sequence of conditionals that operated on individual bytes, making them well-suited for the guided brute-force approach. What seemed perfectly clear, though, is that the algorithm wouldn't be able to get past "atomic", large-search-space checks such as: <p></p> <code>if (strcmp(header.magic_password, "<font color=teal>h4ck3d by p1gZ</font>")) goto terminate_now;</code> <p></p> ...or: <p></p> <code>if (header.magic_value == <font color=teal>0x12345678</font>) goto terminate_now;</code> <p></p> This constraint made the tool less useful for properly exploring extremely verbose, human-readable formats such as HTML or JavaScript. <p></p> Some doubts started to set in when <i>afl-fuzz</i> effortlessly pulled out four-byte magic values and synthesized ELF files when testing programs such as <i>objdump</i> or <i>file</i>. As I later found out, this particular example is often used as a benchmark for complex static analysis or symbolic execution frameworks. But still, guessing four bytes could have been just a happy accident. With fast targets, the fuzzer can pull off billions of execs per day on a single machine, so it could have been dumb luck. <p></p> (As an aside: to deal with strings, I had this very speculative idea of special-casing memory comparison functions such as <i>strcmp()</i> and <i>memcmp()</i> by replacing them with non-optimized versions that can be instrumented easily. I have one simple demo of that principle bundled with the fuzzer in <i>experimental/instrumented_cmp/</i>, but I never got around to actually implementing it in the fuzzer itself.) <p></p> Anyway, nothing quite prepared me for what the recent versions were capable of doing with <i>libxml2</i>. I seeded the session with: <p></p> <xmp><a b="c">d</a></xmp> <p></p> ...and simply used that as the input for a vanilla copy of <i>xmllint</i>. I was merely hoping to stress-test the very basic aspects of the parser, without getting into any higher-order features of the language. Yet, after two days on a single machine, I found this buried in test case #4641 in the output directory: <p></p> <code>...<font color=crimson>&lt;![&lt;CDATA[</font>C%Ada b="c":]<font color=crimson>]]&gt;</font>...</code> <p></p> <b>What the heck?!</b> <p></p> As most of you probably know, <a href='https://en.wikipedia.org/wiki/CDATA'>CDATA</a> is a special, differently parsed section within XML, separated from everything else by fairly complex syntax - a nine-character sequence of bytes that can't be realistically discovered by just randomly flipping bits. <p></p> The finding is actually not magic; there are two possible explanations: <p></p> <ul> <li> As a recent "well, it's cheap, so let's see what happens" optimization, AFL automatically sets <i>-O3 -funroll-loops</i> when calling the compiler for instrumented binaries, and some of the shorter fixed-string comparisons will be actually just expanded inline. For example, if the stars align just right, <i>strcmp(buf, "foo")</i> may be unrolled to: <pre> cmpb $0x66,0x200c32(%rip) # 'f' jne 4004b6 <main+0x46> cmpb $0x6f,0x200c2a(%rip) # 'o' jne 4004b6 <main+0x46> cmpb $0x6f,0x200c22(%rip) # 'o' jne 4004b6 <main+0x46> cmpb $0x0,0x200c1a(%rip) # NUL jne 4004b6 <main+0x46> </pre> ...which, by the virtue of having a series of explicit and distinct branch points, can be readily instrumented on a per-character basis by <i>afl-fuzz</i>. <p></p> <li> If that fails, it just so happens that some of the string comparisons in <i>libxml2</i> in <i>parser.c</i> are done using a bunch of macros that will compile to similarly-structured code (as spotted by Ben Hawkes). This is presumably done so that the compiler can optimize this into a tree-style parser - whereas a linear sequence of <i>strcmp()</i> calls would lead to repeated and unnecessary comparisons of the already-examined chars. <p></p> (Although done by hand in this particular case, the pattern is fairly common for automatically generated parsers of all sorts.) </ul> The progression of test cases seems to support both of these possibilities: <p></p> <code> &lt;![<br> &lt;![C b="c"&gt;<br> &lt;![CDb m="c"&gt;<br> &lt;![CDAĹĹ@<br> &lt;![CDAT&lt;!<br> ... </code> <p></p> I find this result a bit spooky because it's an example of the fuzzer defiantly and secretly working around one of its intentional and explicit design limitations - and definitely not something I was aiming for =) <p></p> Of course, treat this first and foremost as a novelty; there are many other circumstances where similar types of highly verbose text-based syntax would not be discoverable to <i>afl-fuzz</i> - or where, even if the syntax could be discovered through some special-cased shims, it would be a waste of CPU time to do it with <i>afl-fuzz</i>, rather than a simple syntax-aware, template-based tool. <p></p> (Coming up with an API to make template-based generators pluggable into AFL may be a good plan.) <p></p> By the way, here are some other gems from the randomly generated test cases: <p></p> <code>&lt;!DOCTY.<br> &lt;?xml version="2.666666666666666666667666666"&gt;<br> &lt;?xml standalone?&gt;</code> <p></p>Unknown[email protected]4tag:blogger.com,1999:blog-383549007228220941.post-33555736832303411552014-11-24T22:00:00.002-08:002014-11-25T07:20:35.961-08:00afl-fuzz: crash exploration modeOne of the most labor-intensive portions of any fuzzing project is the work needed to determine if a particular crash poses a security risk. A small minority of all fault conditions will have obvious implications; for example, attempts to write or jump to addresses that clearly come from the input file do not need any debate. But most crashes are more ambiguous: some of the most common issues are NULL pointer dereferences and reads from oddball locations outside the mapped address space. Perhaps they are a manifestation of an underlying vulnerability; or perhaps they are just harmless non-security bugs. Even if you prefer to err on the side of caution and treat them the same, the vendor may not share your view. <p></p> If you have to make the call, sifting through such crashes may require spending hours in front of a debugger - or, more likely, rejecting a good chunk of them based on not much more than a hunch. To help triage the findings in a more meaningful way, I decided to add a pretty unique and nifty feature to <i><a href='http://lcamtuf.coredump.cx/afl'>afl-fuzz</a></i>: the brand new <b>crash exploration mode</b>, enabled via <i>-C</i>. <p></p> The idea is very simple: you take a crashing test case and give it to <i>afl-fuzz</i> as a starting point for the automated run. The fuzzer then uses its usual feedback mechanisms and genetic algorithms to see how far it can get within the instrumented codebase while still keeping the program in the crashing state. Mutations that stop the crash from happening are thrown away; so are the ones that do not alter the execution path in any appreciable way. The occasional mutation that makes the crash happen in a subtly different way will be kept and used to seed subsequent fuzzing rounds later on. <p></p> The beauty of this mode is that it very quickly produces a small corpus of related but somewhat different crashes that can be effortlessly compared to pretty accurately estimate the degree of control you have over the faulting address, or to figure out whether you can get past the initial out-of-bounds read by nudging it just the right way (and if the answer is yes, you probably get to see what happens next). It won't necessarily beat thorough code analysis, but it's still pretty cool: it lets you make a far more educated guess without having to put in any work. <p></p> As an admittedly trivial example, let's take a suspect but ambiguous crash in <i>unrtf</i>, found by <i>afl-fuzz</i> in its normal mode: <p></p> <code>unrtf[7942]: segfault at <font color=crimson>450</font> ip 0805062b sp bf957e60 error 4 in unrtf[8048000+1c000]</code> <p></p> When fed to the crash explorer, the fuzzer took just several minutes to notice that by changing <i>{\cb-44901990</i> in the converted RTF file to printable representations of other negative integers, it could quickly trigger faults at arbitrary addresses of its choice, corresponding mostly-linearly to the integer set: <p></p> <p></p> <code>unrtf[28809]: segfault at <font color=crimson>88077782</font> ip 0805062b sp bff00210 error 4 in unrtf[8048000+1c000]<br> unrtf[26656]: segfault at <font color=crimson>7271250</font> ip 0805062b sp bf957e60 error 4 in unrtf[8048000+1c000]</code> <p></p> Given a bit more time, it would also almost certainly notice that choosing values within the mapped address space get it past the crashing location and permit even more fun. So, automatic exploit writing next?Unknown[email protected]1tag:blogger.com,1999:blog-383549007228220941.post-66960456536022655592014-11-07T15:03:00.004-08:002021-05-19T15:04:49.235-07:00Pulling JPEGs out of thin air<p><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">This is an interesting demonstration of the capabilities of&nbsp;</span><a href="https://web.archive.org/web/20210123021417/http://code.google.com/p/american-fuzzy-lop" style="background-color: white; color: #006699; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">afl</a><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">; I was actually pretty surprised that it worked!</span></p><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><pre style="background-color: white; color: #666666;">$ mkdir in_dir $ echo '<span style="color: crimson;">hello</span>' &gt;in_dir/hello $ ./afl-fuzz -i in_dir -o out_dir <span style="color: steelblue;">./jpeg-9a/djpeg</span></pre><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">In essence, I created a text file containing just "hello" and asked the fuzzer to keep feeding it to a program that expects a JPEG image (</span><i style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">djpeg</i><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">&nbsp;is a simple utility bundled with the ubiquitous&nbsp;</span><i style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"><a href="https://web.archive.org/web/20210123021417/http://www.ijg.org/" style="color: #006699;">IJG jpeg</a></i><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">&nbsp;image library;&nbsp;</span><a href="https://web.archive.org/web/20210123021417/http://libjpeg-turbo.virtualgl.org/" style="background-color: white; color: #006699; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"><i>libjpeg-turbo</i></a><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">&nbsp;should also work). Of course, my input file does not resemble a valid picture, so it gets immediately rejected by the utility:</span><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><pre style="background-color: white; color: #666666;">$ ./djpeg '../out_dir/queue/id:000000,orig:hello' <span style="color: crimson;">Not a JPEG file: starts with 0x68 0x65</span></pre><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">Such a fuzzing run would be normally completely pointless: there is essentially no chance that a "hello" could be ever turned into a valid JPEG by a traditional, format-agnostic fuzzer, since the probability that dozens of random tweaks would align just right is astronomically low.</span><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">Luckily,&nbsp;</span><i style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">afl-fuzz</i><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">&nbsp;can leverage lightweight assembly-level instrumentation to its advantage - and within a millisecond or so, it notices that although setting the first byte to&nbsp;</span><i style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">0xff</i><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">&nbsp;does not change the externally observable output, it triggers a slightly different internal code path in the tested app. Equipped with this information, it decides to use that test case as a seed for future fuzzing rounds:</span><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><pre style="background-color: white; color: #666666;">$ ./djpeg '../out_dir/queue/id:000001,src:000000,op:int8,pos:0,val:-1,+cov' <span style="color: crimson;">Not a JPEG file: starts with 0xff 0x65</span></pre><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">When later working with that second-generation test case, the fuzzer almost immediately notices that setting the second byte to&nbsp;</span><i style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">0xd8</i><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">&nbsp;does something even more interesting:</span><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><pre style="background-color: white; color: #666666;">$ ./djpeg '../out_dir/queue/id:000004,src:000001,op:havoc,rep:16,+cov' <span style="color: crimson;">Premature end of JPEG file JPEG datastream contains no image</span></pre><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">At this point, the fuzzer managed to synthesize the valid file header - and actually realized its significance. Using this output as the seed for the next round of fuzzing, it quickly starts getting deeper and deeper into the woods. Within several hundred generations and several hundred million&nbsp;</span><i style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">execve()</i><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">&nbsp;calls, it figures out more and more of the essential control structures that make a valid JPEG file - SOFs, Huffman tables, quantization tables, SOS markers, and so on:</span><pre style="background-color: white; color: #666666;">$ ./djpeg '../out_dir/queue/id:000008,src:000004,op:havoc,rep:2,+cov' <span style="color: crimson;">Invalid JPEG file structure: two SOI markers</span> <span style="color: grey;">...</span> $ ./djpeg '../out_dir/queue/id:001005,src:000262+000979,op:splice,rep:2' <span style="color: crimson;">Quantization table 0x0e was not defined</span> <span style="color: grey;">...</span> $ ./djpeg '../out_dir/queue/id:001282,src:001005+001270,op:splice,rep:2,+cov' &gt;.tmp; ls -l .tmp <span style="color: steelblue;">-rw-r--r-- 1 lcamtuf lcamtuf 7069 Nov 7 09:29 .tmp</span></pre><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">The first image, hit after about six hours on an 8-core system, looks very unassuming: it's a blank grayscale image, 3 pixels wide and 784 pixels tall. But the moment it is discovered, the fuzzer starts using the image as a seed - rapidly producing a wide array of more interesting pics for every new execution path:</span><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><img height="341" src="https://web.archive.org/web/20210123021417im_/https://blogger.googleusercontent.com/img/proxy/AVvXsEhpS9yMIOTwBww2ylGwYx3AX3MDtA-VxZXZLnMBpUqbNfvyt52zlsbyAsP9Pr6rSmhbH7_XVyfOpOUSnefOgOCrAHnG2EAdKpVSzfXEL7PYXnkATc3Gnt823KT15xjCEOCV3ZQBLWjPe-_pskiv0of12pnG=s0-d" style="background-color: white; border: 1px solid teal; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;" width="800" /><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></span><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">Of course, synthesizing a complete image out of thin air is an extreme example, and not necessarily a very practical one. But more prosaically, fuzzers are meant to stress-test every feature of the targeted program. With instrumented, generational fuzzing, lesser-known features (e.g., progressive, black-and-white, or arithmetic-coded JPEGs) can be&nbsp;</span><a href="https://web.archive.org/web/20210123021417/http://lcamtuf.coredump.cx/afl_demo/" style="background-color: white; color: #006699; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">discovered and locked onto</a><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">&nbsp;without requiring a giant, high-quality corpus of diverse test cases to seed the fuzzer with.</span><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">The cool part of the&nbsp;</span><i style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">libjpeg</i><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">&nbsp;demo is that it works without any special preparation: there is nothing special about the "hello" string, the fuzzer knows nothing about image parsing, and is not designed or fine-tuned to work with this particular library. There aren't even any command-line knobs to turn. You can throw&nbsp;</span><i style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">afl-fuzz</i><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">&nbsp;at many other types of parsers with similar results: with bash, it will&nbsp;</span><a href="https://web.archive.org/web/20210123021417/http://lcamtuf.blogspot.com/2014/10/bash-bug-how-we-finally-cracked.html" style="background-color: white; color: #006699; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">write valid scripts</a><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">; with&nbsp;</span><i style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">giflib</i><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">, it will make GIFs; with&nbsp;</span><i style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">fileutils</i><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">, it will create and flag ELF files, Atari 68xxx executables, x86 boot sectors, and UTF-8 with BOM. In almost all cases, the performance impact of instrumentation is minimal, too.</span><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">Of course, not all is roses; at its core,&nbsp;</span><i style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">afl-fuzz</i><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">&nbsp;is still a brute-force tool. This makes it simple, fast, and robust, but also means that certain types of atomically executed checks with a large search space may pose an insurmountable obstacle to the fuzzer; a good example of this may be:</span><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><pre style="background-color: white; color: #666666;">if (strcmp(header.magic_password, <span style="color: steelblue;">"h4ck3d by p1gZ"</span>)) goto terminate_now;</pre><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">In practical terms, this means that&nbsp;</span><i style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">afl-fuzz</i><span style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">&nbsp;won't have as much luck "inventing" PNG files or non-trivial HTML documents from scratch - and will need a starting point better than just "hello". To consistently deal with code constructs similar to the one shown above, a general-purpose fuzzer would need to understand the operation of the targeted binary on a wholly different level. There is some progress on this in the academia, but frameworks that can pull this off across diverse and complex codebases in a quick, easy, and reliable way are probably still years away.</span><p style="background-color: white; color: #111111; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;"></p><span style="background-color: white; color: grey; font-family: Georgia, Trebuchet, &quot;Trebuchet MS&quot;, Arial, sans-serif; font-size: 16px;">PS. Several folks asked me about symbolic execution and other inspirations for&nbsp;<i>afl-fuzz</i>; I put together some notes in&nbsp;<a href="https://web.archive.org/web/20210123021417/http://lcamtuf.coredump.cx/afl_demo/long_story.txt" style="color: #006699;">this doc</a>.</span>Unknown[email protected]0tag:blogger.com,1999:blog-383549007228220941.post-23497333150433463362014-10-24T21:49:00.001-07:002014-10-26T15:11:46.781-07:00PSA: don't run 'strings' on untrusted files (CVE-2014-8485)Many shell users, and certainly most of the people working in computer forensics or other fields of information security, have a habit of running <i>/usr/bin/strings</i> on binary files originating from the Internet. Their understanding is that the tool simply scans the file for runs of printable characters and dumps them to <i>stdout</i> - something that is very unlikely to put you at any risk. <p></p> It is much less known that the Linux version of <i>strings</i> is an integral part of <i><a href='http://www.gnu.org/s/binutils/'>GNU binutils</a></i>, a suite of tools that specializes in the manipulation of several dozen executable formats using a bundled library called <i><a href='https://en.wikipedia.org/wiki/Binary_File_Descriptor_library'>libbfd</a></i>. Other well-known utilities in that suite include <i>objdump</i> and <i>readelf</i>. <p></p> Perhaps simply by the virtue of being a part of that bundle, the <i>strings</i> utility tries to leverage the common <i>libbfd</i> infrastructure to detect supported executable formats and "optimize" the process by extracting text only from specific sections of the file. Unfortunately, the underlying library can be hardly described as safe: a quick pass with <i><a href='https://code.google.com/p/american-fuzzy-lop/'>afl</a></i> (and probably with any other competent fuzzer) quickly reveals a range of troubling and likely exploitable out-of-bounds crashes due to very limited range checking, say: <p></p> <pre> $ wget <a href='http://lcamtuf.coredump.cx/strings-bfd-badptr'>http://lcamtuf.coredump.cx/strings-bfd-badptr2</a> <font color=gray>...</font> $ strings strings-bfd-badptr2 Segmentation fault <font color=gray>...</font> strings[24479]: segfault at <font color=crimson>4141416d</font> ip 0807a4e7 sp bf80ca60 error 4 in strings[8048000+9a000] <font color=gray>...</font> while (--n_elt != 0) if ((++idx)->shdr->bfd_section) <font color=purple> &larr; Read from an attacker-controlled pointer</font> elf_sec_group (idx->shdr->bfd_section) = shdr->bfd_section; <font color=purple> &larr; Write to an attacker-controlled pointer</font> <font color=gray>...</font> (gdb) p idx->shdr $1 = (Elf_Internal_Shdr *) <font color=crimson>0x41414141</font> </pre> <p></p> The 0x41414141 pointer being read and written by the code comes directly from that proof-of-concept file and can be freely modified by the attacker to try overwriting program control structures. Many Linux distributions ship <i>strings</i> without ASLR, making potential attacks easier and more reliable - a situation reminiscent of one of the recent bugs in <i><a href='http://lcamtuf.blogspot.com/2014/10/bash-bug-how-we-finally-cracked.html'>bash</a></i>. <p></p> Interestingly, the problems with the utility aren't exactly new; Tavis spotted the first signs of trouble some <a href='https://bugs.gentoo.org/show_bug.cgi?id=91398'>nine years ago</a>. <p></p> In any case: the bottom line is that if you are used to running <i>strings</i> on random files, or depend on any <i>libbfd</i>-based tools for forensic purposes, you should probably change your habits. For <i>strings</i> specifically, invoking it with the <i>-a</i> parameter seems to inhibit the use of <i>libbfd</i>. Distro vendors may want to consider making the <i>-a</i> mode default, too. <p></p> <i> <font color=gray> PS. I actually had the libbfd fuzzing job running on <a href='http://lcamtuf.coredump.cx/edison_fuzz/'>this thing</a>! </font> </i> Unknown[email protected]15tag:blogger.com,1999:blog-383549007228220941.post-84132020578201005352014-10-14T12:10:00.000-07:002014-12-09T11:48:21.781-08:00Two more browser memory disclosure bugs (CVE-2014-1580 and #19611cz)To add several more trophies to <a href='http://code.google.com/p/american-fuzzy-lop/'>afl</a>'s pile of <a href='http://lcamtuf.blogspot.com/2014/08/a-bit-more-about-american-fuzzy-lop.html'>image parsing memory disclosure vulnerabilities</a>: <ul> <li> <b><a href='https://www.mozilla.org/security/announce/2014/mfsa2014-78.html'>MSFA 2014-78</a></b> (CVE-2014-1580) fixes another case of uninitialized memory disclosure in Firefox - this time, when rendering truncated GIF images on <code>&lt;canvas&gt;</code>. The bug was reported on September 5 and fixed today. For a convenient test case, check out <a href='http://lcamtuf.coredump.cx/ffgif2/'>this page</a>. Rough timeline: <p></p> <ul> <li><b>September 5:</b> Initial, admittedly brief notification to vendor, including a <a href='http://lcamtuf.coredump.cx/ffgif2/'>simple PoC</a>. <li><b>September 5:</b> Michael Wu confirms the exposure and pinpoints the root cause. Discussion of fixes ensues. <li><b>September 9:</b> Initial patch created. <li><b>September 12:</b> Patch approved and landed. <li><b>October 2:</b> Patch verified by QA. <li><b>October 13:</b> Fixes ship with Firefox 33. </ul> <p></p> <li> <b>MSRC case #19611cz</b> (<a href='https://technet.microsoft.com/library/security/ms14-085'>MS14-085</a>) is a conceptually similar bug related to JPEG DHT parsing, seemingly leaking bits of stack information in Internet Explorer. This was reported to MSRC on July 2 and hasn't been fixed to date. Test case <a href='http://lcamtuf.coredump.cx/iepuzzle/canvas.html'>here</a>. Rough timeline: <p></p> <ul> <li><b>July 2:</b> Initial, admittedly brief notification to vendor, mentioning the disclosure of uninitialized memory and including a <a href='http://lcamtuf.coredump.cx/iepuzzle/'>simple PoC</a>. <li><b>July 3:</b> MSRC request to provide "steps and necessary files to reproduce". <li><b>July 3:</b> My response, pointing back to the original test case. <li><b>July 3:</b> MSRC response, stating that they are "unable to determine the nature of what I am reporting". <li><b>July 3:</b> My response, reiterating the suspected exposure in a more verbose way. <li><b>July 4:</b> MSRC response from an analyst, confirming that they could reproduce, but also wondering if "his webserver is not loading up a different jpeg just to troll us". <li><b>July 4:</b> My response stating that I'm not trolling MSRC. <li><b>July 4:</b> MSRC opens case #19611cz. <li><b>July 29:</b> MSRC response stating that they are "unable identify a way in which an attacker would be able to propagate the leaked stack data back to themselves". <li><b>July 29:</b> My response pointing the existence of the <a href='http://msdn.microsoft.com/en-us/library/ie/ff975241(v=vs.85).aspx'>canvas.toDataURL()</a> API in Internet Explorer, and providing a <a href='http://lcamtuf.coredump.cx/iepuzzle/canvas.html'>new PoC</a> that demonstrates the ability to read back data. <li><b>September 24:</b> A notification from MSRC stating that the case has been transferred to a new case manager. <li><b>October 7:</b> My response noting that we've crossed the 90-day mark with no apparent progress made, and that I plan to disclose the bug within a week. <li><b>October 9:</b> Acknowledgment from MSRC. </ul> </ul> Well, that's it. Enjoy!Unknown[email protected]0tag:blogger.com,1999:blog-383549007228220941.post-86058422325136236452014-10-14T02:02:00.002-07:002014-10-14T07:45:03.190-07:00Fuzzing random programs without execve()The most common way to fuzz data parsing libraries is to find a simple binary that exercises the interesting functionality, and then simply keep executing it over and over again - of course, with slightly different, randomly mutated inputs in each run. In such a setup, testing for evident memory corruption bugs in the library can be as simple as doing <i>waitpid()</i> on the child process and checking if it ever dies with <i>SIGSEGV</i>, <i>SIGABRT</i>, or something equivalent. <p></p> This approach is favored by security researchers for two reasons. Firstly, it eliminates the need to dig into the documentation, understand the API offered by the underlying library, and then write custom code to stress-test the parser in a more direct way. Secondly, it makes the fuzzing process repeatable and robust: the program is running in a separate process and is restarted with every input file, so you do not have to worry about a random memory corruption bug in the library clobbering the state of the fuzzer itself, or having weird side effects on subsequent runs of the tested tool. <p></p> Unfortunately, there is also a problem: especially for simple libraries, you may end up spending most of the time waiting for <i>execve()</i>, the linker, and all the library initialization routines to do their job. I've been thinking of ways to minimize this overhead in <a href='http://code.google.com/p/american-fuzzy-lop'>american fuzzy lop</a>, but most of the ideas I had were annoyingly complicated. For example, it is possible to write a custom ELF loader and execute the program in-process while using <i>mprotect()</i> to temporarily lock down the memory used by the fuzzer itself - but things such as signal handling would be a mess. Another option would be to execute in a single child process, make a snapshot of the child's process memory and then "rewind" to that image later on via <i>/proc/pid/mem</i> - but likewise, dealing with signals or file descriptors would require a ton of fragile hacks. <p></p> Luckily, <a href='http://thejh.net/'>Jann Horn</a> figured a different, much simpler approach, and sent me a patch for <i>afl</i> out of the blue :-) It boils down to injecting a small piece of code into the fuzzed binary - a feat that can be achieved via <i>LD_PRELOAD</i>, via <i>PTRACE_POKETEXT</i>, via compile-time instrumentation, or simply by rewriting the ELF binary ahead of the time. The purpose of the injected shim is to let <i>execve()</i> happen, get past the linker (ideally with <i>LD_BIND_NOW=1</i>, so that all the hard work is done beforehand), and then stop early on in the actual program, before it gets to processing any inputs generated by the fuzzer or doing anything else of interest. In fact, in the simplest variant, we can simply stop at <i>main()</i>. <p></p> Once the designated point in the program is reached, our shim simply waits for commands from the fuzzer; when it receives a "go" message, it calls <i>fork()</i> to create an identical clone of the already-loaded program; thanks to the powers of copy-on-write, the clone is created very quickly yet enjoys a robust level of isolation from its older twin. Within the child process, the injected code returns control to the original binary, letting it process the fuzzer-supplied input data (and suffer any consequences of doing so). Within the parent, the shim relays the PID of the newly-crated process to the fuzzer and goes back to the command-wait loop. <p></p> Of course, when you start dealing with process semantics on Unix, nothing is as easy as it appears at first sight; here are some of the gotchas we had to work around in the code: <ul> <li> File descriptor offsets are shared between processes created with <i>fork()</i>. This means that any descriptors that are open at the time that our shim is executed may need to be rewound to their original position; not a significant concern if we are stopping at <i>main()</i> - we can just as well rewind stdin by doing <i>lseek()</i> in the fuzzer itself, since that's where the descriptor originates - but it can become a hurdle if we ever aim at locations further down the line. <p></p> <li> In the same vein, there are some types of file descriptors we can't fix up. The shim needs to be executed before any access to pipes, character devices, sockets, and similar non-resettable I/O. Again, not a big concern for <i>main()</i>. <p></p> <li> The task of duplicating threads is more complicated and would require the shim to keep track of them all. So, in simple implementations, the shim needs to be injected before any additional threads are spawned in the binary. (Of course, threads are rare in file parser libraries, but may be more common in more heavyweight tools.) <p></p> <li> The fuzzer is no longer an immediate parent of the fuzzed process, and as a grandparent, it can't directly use <i>waitpid()</i>; there is also no other simple, portable API to get notified about the process' exit status. We fix that simply by having the shim do the waiting, then send the status code to the fuzzer. In theory, we should simply call the <i>clone()</i> syscall with the <i>CLONE_PARENT</i> flag, which would make the new process "inherit" the original PPID. Unfortunately, calling the syscall directly confuses glibc, because the library caches the result of <i>getpid()</i> when initializing - and without a way to make it reconsider, PID-dependent calls such as <i>abort()</i> or <i>raise()</i> will go astray. There is also a library wrapper for the <i>clone()</i> call that does update the cached PID - but the wrapper is unwieldy and insists on messing with the process' stack. <p></p> (To be fair, PTRACE_ATTACH offers a way to temporarily adopt a process and be notified of its exit status, but it also changes process semantics in a couple of ways that need a fair amount of code to fully undo.) </ul> Even with the gotchas taken into account, the shim isn't complicated and has very few moving parts - a welcome relief compared to the solutions I had in mind earlier on. It reads commands via a pipe at file descriptor 198, uses fd 199 to send messages back to parent, and does just the bare minimum to get things sorted out. A slightly abridged verion of the code is: <pre> __afl_forkserver: /* Phone home and tell the parent that we're OK. */ pushl $4 /* length */ pushl $__afl_temp /* data */ pushl $199 /* file desc */ call write addl $12, %esp __afl_fork_wait_loop: /* Wait for parent by reading from the pipe. This will block until the parent sends us something. Abort if read fails. */ pushl $4 /* length */ pushl $__afl_temp /* data */ pushl $198 /* file desc */ call read addl $12, %esp cmpl $4, %eax jne __afl_die /* Once woken up, create a clone of our process. */ call fork cmpl $0, %eax jl __afl_die je __afl_fork_resume /* In parent process: write PID to pipe, then wait for child. Parent will handle timeouts and SIGKILL the child as needed. */ movl %eax, __afl_fork_pid pushl $4 /* length */ pushl $__afl_fork_pid /* data */ pushl $199 /* file desc */ call write addl $12, %esp pushl $2 /* WUNTRACED */ pushl $__afl_temp /* status */ pushl __afl_fork_pid /* PID */ call waitpid addl $12, %esp cmpl $0, %eax jle __afl_die /* Relay wait status to pipe, then loop back. */ pushl $4 /* length */ pushl $__afl_temp /* data */ pushl $199 /* file desc */ call write addl $12, %esp jmp __afl_fork_wait_loop __afl_fork_resume: /* In child process: close fds, resume execution. */ pushl $198 call close pushl $199 call close addl $8, %esp ret </pre> But, was it worth it? The answer is a resounding "yes": the stop-at-<i>main()</i> logic, already shipping with <i>afl 0.36b</i>, can speed up the fuzzing of many common image libraries by a factor of two or more. It's actually almost unexpected, given that we still keep doing <i>fork()</i>, a syscall with a lingering reputation for being very slow. <p></p> The next challenge is devising a way to move the shim down the stream, so that we can also skip any common program initialization steps, such as reading config files - and stop just few instructions shy of the point where the application tries to read the mutated data we are messing with. Jann's original patch has a solution that relies on <i>ptrace()</i> to detect file access; but we've been brainstorming several other ways. <p></p> <span style='color: gray'>PS. On a related note, some readers might enjoy <a href='http://lcamtuf.coredump.cx/edison_fuzz/'>this</a>.</span> Unknown[email protected]2tag:blogger.com,1999:blog-383549007228220941.post-90027363262502509182014-10-01T07:25:00.000-07:002014-10-02T01:27:08.436-07:00Bash bug: the other two RCEs, or how we chipped away at the original fix (CVE-2014-6277 and '78)The patch that implements a prefix-based way to mitigate vulnerabilities in bash function exports has been <a href='http://www.openwall.com/lists/oss-security/2014/09/25/13'>out since last week</a> and has been already picked up by most Linux vendors (plus by Apple). So, here's a quick overview of the key developments along the way, including two really interesting things: proof-of-concept test cases for two serious, previously non-public RCE bugs tracked as CVE-2014-6277 and CVE-2014-6278. <p></p> <i><b>NOTE: If you or your distro maintainers have already deployed Florian's patch, there is no reason for alarm - you are almost certainly not vulnerable to attacks. If you do not have this patch, and instead relied only on the original CVE-2014-6271 fix, you probably need to act now. See <a href='http://lcamtuf.blogspot.com/2014/09/bash-bug-apply-unofficial-patch-now.html'>this entry</a> for a convenient test case and other tips.</b></i> <p></p> Still here? Good. If you need a refresher, the basic principles of the underlying function export functionality, and the impact of the original bash bug (CVE-2014-6271), are discussed in <a href='http://lcamtuf.blogspot.com/2014/09/quick-notes-about-bash-bug-its-impact.html'>this blog post</a>. If you have read the earlier post, the original attack disclosed by Stephane Chazelas should be very easy to understand: <p></p> <code>HTTP_COOKIE='() { 0; }; <font color='crimson'>echo hi mom;</font>' bash -c :</code> <p></p> In essence, the internal parser invoked by bash to process the specially encoded function definitions passed around in environmental variables had a small problem: it continued parsing the code past the end of the function definition itself - and at that point, flat out executed whatever instructions it came across, just as it would do in a normal bash script. Given that the value of certain environmental variables can be controlled by remote attackers in quite a few common settings, this opened up a good chunk of the Internet to attacks. <p></p> The original vulnerability was reported privately and kept under embargo for roughly two weeks to develop a fairly conservative fix that modified the parser to bail out in a timely manner and do not parse any trailing commands. As soon as the embargo was lifted, we all found out about the bug and scrambled to deploy fixes. At the same time, a good chunk of the security community reacted with surprise and disbelief that bash is keen to dispatch the contents of environmental variables to a fairly complex syntax parser - so we started poking around. <p></p> Tavis was the quickest: he found that you can convince the parser to keep looking for a file name for output redirection past the boundary between the untrusted string accepted from the environment and the actual body of the program that bash is being asked to execute (CVE-2014-7169). His original test case can be simplified at: <p></p> <code>HTTP_COOKIE='() { function a <font color='crimson'>a>\</font>' bash -c echo</code> <p></p> This example would create an empty file named "echo", instead of executing the requested command. Tavis' finding meant that you would be at risk of remote code execution in situations where attacker-controlled environmental variables are mixed with sanitized, attacker-controlled command-line parameters passed to calls such as <code>system()</code> or <code>popen()</code>. For example, you'd be in trouble if you were doing this in a web app: <p></p> <code>system("echo '"+ <font color=crimson>sanitized_string_without_quotes</font> + "' | /some/trusted/program"); </code> <p></p> ...because the attacker could convince bash to skip over the "echo" command and execute the command given in the second parameter, which happens to be a sanitized string (albeit probably with no ability to specify parameters). On the flip side, this is a fairly specific if not entirely exotic coding pattern - and contrary to some of the initial reports, the bug probably wasn't exploitable in a much more general way. <p></p> Chet, the maintainer of bash, started working on a fix to close this specific parsing issue, and released it <a href='http://ftp.gnu.org/gnu/bash/bash-4.3-patches/bash43-026'>soon thereafter</a>. <p></p> On the same day, Todd Sabin and Florian Weimer have independently bumped into a static array overflow in the parser (CVE-2014-7186). The bug manifested in what seemed to be a non-exploitable crash, trying to dereference a non-attacker-controlled pointer at an address that "by design" should fall well above the end of heap - but was enough to cast even more doubt on the robustness of the underlying code. The test for this problem was pretty simple - you just needed a sequence of here-documents that overflowed a static array, say: <p></p> <code>HTTP_COOKIE='() { 0 <font color='crimson'>&lt;&lt;a &lt;&lt;b &lt;&lt;c &lt;&lt;d &lt;&lt;e &lt;&lt;f &lt;&lt;g &lt;&lt;h &lt;&lt;i &lt;&lt;j &lt;&lt;k &lt;&lt;l &lt;&lt;m;</font> }' bash -c :</code> <p></p> Florian also bumped into an off-by-one issue with loop parsing (CVE-2014-7187); the proof-of-concept function definition for this is a trivial <code>for</code> loop nested 129 levels deep, but the effect can be only observed under memory access diagnostics tools, and its practical significance is probably low. Nevertheless, all these revelations prompted him to start working on an unofficial but far more comprehensive patch that would largely shield the parser from untrusted strings in normally encountered variables present in the environment. <p></p> In parallel to Tavis' and Florian's work, I set up a very straightforward fuzzing job with <a href='https://code.google.com/p/american-fuzzy-lop/'>american fuzzy lop</a>. I seeded it with a rudimentary function definition: <xmp>() { foo() { foo; }; >bar; } </xmp> ...and simply let it run with a minimalistic wrapper that took the test case generated by the fuzzer, put it in a variable, and then called <code>execve()</code> to invoke bash. <p></p> Although the fuzzer had no clue about the syntax of shell programs, it had the benefit of being able to identify and isolate interesting syntax based on coverage signals, deriving around 1,000 other distinctive test cases from the starting one while "instinctively" knowing not to mess with the essential "() {" prefix. For the first few hours, it kept hitting only the redirect issue originally reported by Todd and the file-creation issue discovered by Tavis - but soon thereafter, it spewed out a new crash illustrated by this snippet of code (<b>CVE-2014-6277</b>): <p></p> <code>HTTP_COOKIE='() { x() { _; }; x() { _; } <font color=crimson>&lt;&lt;a</font>; }' bash -c :</code> <p></p> This proved to be a very straightforward use of uninitialized memory: it hit a code path in <code>make_redirect()</code> where one field in a newly-allocated <code>REDIR</code> struct - <code>here_doc_eof</code> - would not be set to any specific value, yet would be treated as a valid pointer later on (somewhere in <code>copy_redirect()</code>). <p></p> Now, if bash is compiled with both <code>--enable-bash-malloc</code> and <code>--enable-mem-scramble</code>, the memory returned to <code>make_redirect()</code> by <code>xmalloc()</code> will be set to <code>0xdf</code>, making the pointer always resolve to <code>0xdfdfdfdf</code>, and thus rendering the prospect of exploitation far more speculative (essentially depending on whether the stack or any other memory region can be grown by the attacker to overlap with this address). That said, on a good majority of Linux distros, these flags are disabled, and you can trivially get bash to dereference a pointer that is entirely within attacker's control: <p></p> <code>HTTP_COOKIE="() { x() { _; }; x() { _; } <font color=crimson>&lt;&lt;`perl -e '{print "A"x1000}'`</font>; }" bash -c :<br> bash[25662]: segfault at <font color='crimson'>41414141</font> ip 00190d96 sp bfbe6354 error 4 in libc-2.12.so[110000+191000] </code> <p></p> The actual fault happens because of an attempt to copy <code>here_doc_eof</code> to a newly-allocated buffer using a C macro that expands to the following code: <p></p> <code>strcpy(xmalloc(1 + strlen(<font color=crimson>redirect->here_doc_eof</font>)), (<font color=crimson>redirect->here_doc_eof</font>))</code> <p></p> This appears to be exploitable in at least one way: if <code>here_doc_eof</code> is chosen by the attacker to point in the vicinity of the current stack pointer, the apparent contents of the string - and therefore its length - may change between stack-based calls to <code>xmalloc()</code> and <code>strcpy()</code> as a natural consequence of an attempt to pass parameters and create local variables. Such a mid-macro switch will result in an out-of-bounds write to the newly-allocated memory. <p></p> A simple conceptual illustration of this attack vector would be: <xmp>char* result; int len_alloced; main(int argc, char** argv) { /* The offset will be system- and compiler-specific */; char* ptr = &ptr - 9; result = strcpy (malloc(100 + (len_alloced = strlen(ptr))), ptr); printf("requested memory = %d\n" "copied text = %d\n", len_alloced + 1, strlen(result) + 1); } </xmp> When compiled with the -O2 flag used for bash, on one test system, this produces: <p></p> <code>requested memory = 2<br> copied text = <font color=crimson>28</font> </code><p></p> Of course, the result will vary from system to system, but the general consequences of this should be fairly evident. The issue is also made worse by the fact that only relatively few distributions were building bash as a position-independent executable that could be fully protected by ASLR. <p></p> (In addition to this vector, there is also a location in <code>dispose_cmd.c</code> that calls <code>free()</code> on the pointer under some circumstances, but I haven't really really spent a lot of time trying to develop a functioning exploit for the '77 bug for reasons that should be evident in the text that follows... well, just about now.) <p></p> It has to be said that there is a bit less glamour to such a low-level issue that still requires you to go through some mental gymnastics to be exploited in a portable way. Luckily, the fuzzer kept going, and few hours later, isolated a test case that, after <a href='http://code.google.com/p/tmin/'>minimization</a>, yielded this gem (<b>CVE-2014-6278</b>): <p></p> <code>HTTP_COOKIE='() { _; } >_[$($())] { <font color="crimson">echo hi mom; id;</font> }' bash -c : </code> <p></p> I am... actually not entirely sure what happens here. A sequence of nested <code>$...</code> statements within a redirect appears to cause the parser to bail out without properly resetting its state, and puts it in the mood for executing whatever comes next. The test case works as-is with bash 4.2 and 4.3, but not with more ancient releases; this is probably related to changes introduced few years ago in bash 4.2 patch level 12 (<code>xparse_dolparen()</code>), but I have not investigated if earlier versions are patently not vulnerable or simply require different syntax. <p></p> The CVE-2014-6278 payload allows straightforward "put-your-commands-here" remote code execution on systems that are protected only with the original patch - something that we were <a href='http://lcamtuf.blogspot.com/2014/09/bash-bug-apply-unofficial-patch-now.html'>worried about</a> for a while, and what prompted us to <a href='http://www.pcworld.com/article/2688932/improved-patch-tackles-new-shellshock-attack-vectors.html'>ask people to update again</a> over the past few days. <p></p> Well, that's it. I kept the technical details of the last two findings embargoed for a while to give people some time to incorporate Florian's patch and avoid the panic associated with the original bug - but at this point, given the scrutiny that the code is under, the ease of discovering the problems with off-the-shelf open-source tools, and the availability of adequate mitigations, the secrecy seems to have outlived its purpose. <p></p> Any closing thoughts? Well, I'm not sure there's a particular lesson to be learnt from the entire story. There's perhaps one thing - it would probably have been helpful if the questionable nature of the original patch was spotted by any of the notified vendors during the two-week embargo period. That said, I wasn't privy to these conversations - and hindsight is always 20/20.Unknown[email protected]11tag:blogger.com,1999:blog-383549007228220941.post-25555287035195212732014-09-27T11:27:00.000-07:002014-10-09T08:06:27.626-07:00Bash bug: apply Florian's patch now (CVE-2014-6277 and CVE-2014-6278)OK, rebuild bash and deploy <a href='http://www.openwall.com/lists/oss-security/2014/09/25/13'>Florian's unofficial patch</a> or its <a href='http://ftp.gnu.org/gnu/bash/bash-4.3-patches/bash43-027'>now-upstream version</a> now. If you're a distro maintainer, please consider doing the same. <p></p> My <a href='http://lcamtuf.blogspot.com/2014/09/quick-notes-about-bash-bug-its-impact.html'>previous post</a> has more information about the original vulnerability (CVE-2014-6271). It also explains Tavis' and my original negative sentiment toward the <a href='http://ftp.gnu.org/gnu/bash/bash-4.3-patches/bash43-025'>original upstream patch</a>. In short, the revised code did not stop bash from parsing the code seen in potentially attacker-controlled, remotely-originating environmental variables. Instead, the fix simply seeks to harden the parsing to prevent RCE. It relies on two risky assumptions: <ul> <li> That spare for this one bug we're fixing now, the process of parsing attacker-controlled functions is guaranteed to have no side effects on the subsequently executed trusted code.<p></p> <li> That the underlying parser, despite probably not being designed to deal with attacker-supplied inputs, is free from the usual range of C language bugs. </ul> From the very early hours, we have argued on the <a href='http://seclists.org/oss-sec/2014/q3/663'>oss-security mailing list</a> that a more reasonable approach would be to shield the parser from remotely-originating strings. I proposed putting the function export functionality behind a runtime flag or using a separate, prefixed namespace for the exported functions - so that variables such as <code>HTTP_COOKIE</code> do not go through this code path at all. Unfortunately, we made no real progress on that early in the game. <p></p> Soon thereafter, people started to bump into additional problems in the parser code. The first assumption behind the patch - the one about the parsing process not having other side effects - was quickly proved wrong by <a href='https://twitter.com/taviso/status/514887394294652929'>Tavis</a>, who came up with a code construct that would get the parser in an inconsistent state, causing bash to create a bogus file and mangle any subsequent code that <code>/bin/sh</code> is supposed to execute. <p></p> This was assigned CVE-2014-7169 and led to a round of high-profile press reports claiming that we're still doomed, and people assigning the new bug <a href='http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-7169'>CVSS scores all the way up to 11</a>. The reality was a bit more nuanced: the glitch demonstrated by Tavis' code is a bit less concerning, because it does not translate into a universally exploitable RCE - at least not as far as we could figure it out. Some uses of <code>/bin/sh</code> would be at risk, but most would just break in a probably-non-exploitable way. The maintainer followed with <a href='http://ftp.gnu.org/gnu/bash/bash-4.3-patches/bash43-026'>another patch</a> that locked down this specific hole. <p></p> The second assumption started showing cracks, too. First came a report from Todd Sabin, who identified an <a href='http://www.openwall.com/lists/oss-security/2014/09/25/32'>static array overflow error</a> when parsing more than ten stacked redirects. The bug, assigned CVE-2014-7186, would cause a crash, but given the nature of the underlying assignment, immediate exploitability seemed fairly unlikely. Another probably non-security off-by-one issue with line counting in loops cropped up shortly thereafter (CVE-2014-7187). <p></p> The two latter issues <u>do not</u> have an officially released upstream patch at that point, but they prompted Florian Weimer of Red Hat to develop an unofficial patch that takes a seemingly more durable approach that we argued for earlier on: <a href='http://www.openwall.com/lists/oss-security/2014/09/25/13'>putting function exports in a separate namespace</a>. Florian's fix effectively isolates the function parsing code from attacker-controlled strings in almost all the important use cases we can currently think of. <p></p> (One major outlier would be any solutions that rely on blacklisting environmental variables to run restricted shells or restricted commands as a privileged user - sudo-type stuff - but it's a much smaller attack surface and a a very dubious security boundary to begin with.) <p></p> Well... so, to get to the point: I've been fuzzing the underlying function parser on the side - and yesterday, bumped into a new parsing issue (CVE-2014-6277) that is almost certainly remotely exploitable and made easier to leverage due to the fact that bash is <a href='https://twitter.com/scarybeasts/status/515774894718459904'>seldom compiled with ASLR</a>. I'll share the technical details later on; for now, I sent the info to the maintainer of bash and to several key Linux distros. In general terms, it's an attempt to access uninitialized memory leading to reads from, and then subsequent writes to, a pointer that is fully within attacker's control. Here's a pretty telling crash: <xmp>bash[3054]: segfault at 41414141 ip 00190d96 ... </xmp> Soon after posting this entry, I also bumped in the sixth and most severe issue so far, essentially permitting very simple and straightforward remote code execution (CVE-2014-6278) on the systems that are patched against the first bug. It's a "put your commands here" type of a bug similar to the original report. I will post additional details in a couple of days to give people enough time to upgrade. <p></p> At this point, I <b>very strongly</b> recommend manually deploying <a href='http://www.openwall.com/lists/oss-security/2014/09/25/13'>Florian's patch</a> unless your distro is already shipping it. (Florian's patch has been also finally included <a href='http://lcamtuf.blogspot.com/2014/09/bash-bug-apply-unofficial-patch-now.html'>upstream</a> shortly after I first posted this entry.) <p></p> From within the shell itself, the simplest way to check if you already have it installed would be: <xmp>_x='() { echo vulnerable; }' bash -c '_x 2>/dev/null || echo not vulnerable' </xmp> If the command shows "vulnerable", you don't have the patch and you are still vulnerable to a (currently non-public) RCE, even if you applied the original one (or the subsequent upstream patch that addressed the issue found by Tavis).Unknown[email protected]13tag:blogger.com,1999:blog-383549007228220941.post-29121807365352602742014-09-25T00:10:00.001-07:002014-10-09T08:05:22.296-07:00Quick notes about the bash bug, its impact, and the fixes so farWe spent a good chunk of the day investigating the <a href='http://www.openwall.com/lists/oss-security/2014/09/24/11'>now-famous bash bug</a> (CVE-2014-6271), so I had no time to make too many jokes about it on Twitter - but I wanted to jot down several things that have been getting drowned out in the noise earlier in the day. <p></p> Let's start with the nature of the bug. At its core, the problem caused by an obscure and little-known feature that allows bash programs to export function definitions from a parent shell to children shells, similarly to how you can export normal environmental variables. The functionality in action looks like this: <xmp>$ function foo { echo "hi mom"; } $ export -f foo $ bash -c 'foo' # Spawn nested shell, call 'foo' hi mom </xmp> The behavior is implemented as a hack involving specially-formatted environmental variables: in essence, any variable starting with a literal "() {" will be dispatched to the parser just before executing the main program. You can see this in action here: <xmp>$ foo='() { echo "hi mom"; }' bash -c 'foo' hi mom </xmp> The concept of granting magical properties to certain values of environmental variables clashes with several ancient customs - most notably, with the tendency for web servers such as Apache to pass client-supplied strings in the environment to any subordinate binaries or scripts. Say, if I request a CGI or PHP script from your server, the env variables <code>$HTTP_COOKIE</code> and <code>$HTTP_USER_AGENT</code> will be probably initialized to the raw values seen in the original request. If the values happen to begin with "() {" and are ever seen by <code>/bin/bash</code>, events may end up taking an unusual turn. <p></p> And so, the bug we're dealing with stems from the observation that trying to parse function-like strings received in <code>HTTP_*</code> variables could have some unintended side effects in that shell - namely, it could easily lead to your server executing arbitrary commands trivially supplied in a HTTP header by random people on the Internet. <p></p> With that out of the way, it is important to note that the <a href='http://ftp.gnu.org/gnu/bash/bash-4.3-patches/bash43-025'>today's patch</a> provided by the maintainer of bash <b>does not</b> stop the shell from trying to parse the code within headers that begin with "() {" - it merely tries to get rid of that particular RCE side effect, originally triggered by appending commands past the end of the actual function def. But even with all the current patches applied, you can still do this: <xmp>Cookie: () { echo "Hello world"; } </xmp> ...and witness a callable function dubbed <code>HTTP_COOKIE()</code> materialize in the context of subshells spawned by Apache; of course, the name will be always prefixed with <code>HTTP_*</code>, so it's unlikely to clash with anything or be called by incident - but intuitively, it's a pretty scary outcome. <p></p> In the same vein, doing this will also have an unexpected result: <xmp>Cookie: () { oops </xmp> If specified on a request to a bash-based CGI script, you will see a scary bash syntax error message in your error log. <p></p> All in all, the fix hinges on two risky assumptions: <ol> <li>That the bash function parser invoked to deal with variable-originating function definitions is robust and does not suffer from the usual range of low-level C string parsing bugs that almost always haunt similar code - a topic that, when it comes to shells, hasn't been studied in much detail before now. (In fact, I am aware of a <s>privately made</s> <a href='http://www.openwall.com/lists/oss-security/2014/09/25/32'>now disclosed</a> report of such errors in the parser - CVE-2014-7186 and CVE-2014-7187.)<p></p> <i>Update (Sep 26): I also bumped into what seems to be a separate and probably exploitable use of an uninitialized pointer in the parser code; shared the details privately upstream.</i><p></p> <li>That the parsing steps are guaranteed to have no global side effects within the child shell. As it happens, this assertion has been already <a href='https://twitter.com/taviso/status/514887394294652929'>proved wrong</a> by Tavis (CVE-2014-7169); the side effect he found <a href='http://www.openwall.com/lists/oss-security/2014/09/24/40'>probably-maybe isn't devastating</a> in the general use case (at least until the next stroke of brilliance), but it's certainly a good reason for concern.<p></p> <i>Update (Sep 26): Found a sixth and most severe issue that is essentially equivalent to the original RCE on all systems that only have the original, maintainer-provided patch.</i><p></p> </ol> Contrary to multiple high-profile reports, the original fix was not "broken" in the sense that there is no universal RCE exploit for it - but if I were a betting man, I would not bet on the patch holding up in the long haul <i>(Update: as noted above, it did not hold up)</i>. A more reasonable solution would involve temporarily disabling function imports, putting them behind a runtime flag, or blacklisting some of the most dangerous variable patterns (e.g., <code>HTTP_*</code>); and later on, perhaps moving to a model where function exports use a <a href='http://www.openwall.com/lists/oss-security/2014/09/25/13'>distinct namespace</a> while present in the environment. <p></p> What else? Oh, of course: the impact of this bug is an interesting story all in itself. At first sight, the potential for remote exploitation should be limited to CGI scripts that start with <code>#!/bin/bash</code> and to several other programs that explicitly request this particular shell. But there's a catch: on a good majority of modern Linux systems, <code>/bin/sh</code> is actually a symlink to <code>/bin/bash</code>! <p></p> This means that web apps written in languages such as PHP, Python, C++, or Java, are <a href='http://www.openwall.com/lists/oss-security/2014/09/24/17'>likely to be vulnerable</a> if they ever use libcalls such as <code>popen()</code> or <code>system()</code>, all of which are backed by calls to <code>/bin/sh -c '...'</code>. There is also some added web-level exposure through <code>#!/bin/sh</code> CGI scripts, <code>&lt;!--#exec cmd="..."&gt;</code> calls in SSI, and possibly more exotic vectors such as <code>mod_ext_filter</code>. <p></p> For the same reason, userland DHCP clients that invoke configuration scripts and use variables to pass down config details are at risk when exposed to rogue servers (e.g., on open wifi). A handful of MTAs, MUAs, or FTP server architectures may be also of concern - in particular, there are third-party reports of <a href='http://marc.info/?l=qmail&m=141183309314366&w=2'>qmail installations being at risk</a>. Finally, there is some exposure for environments that use restricted SSH shells (possibly including Git) or restricted sudo commands, but the security of such approaches is typically fairly modest to begin with. <p></p> Exposure on other fronts is possible, but probably won't be as severe. The worries around PHP and other web scripting languages, along with the concern for userspace DHCP, are the most significant reasons to upgrade - and perhaps to roll out more paranoid patches, rather than relying solely on the two official ones. On the upside, you don't have to worry about non-bash shells - and that covers a good chunk of embedded systems out there. In particular, contrary to several claims, Busybox should be fine. <p></p> <i>Update (Sep 28): the previously-unofficial namespace isolation patch from Florian has eventually made it <a href='http://ftp.gnu.org/gnu/bash/bash-4.3-patches/bash43-027'>upstream</a>. You should deploy that patch <a href='http://lcamtuf.blogspot.com/2014/09/bash-bug-apply-unofficial-patch-now.html'>ASAP</a>.</i> <p></p> <span style="color: gray"><i>PS. As for the inevitable "why hasn't this been noticed for 15 years" / "I bet the NSA knew about it" stuff - my take is that it's a very unusual bug in a very obscure feature of a program that researchers don't really look at, precisely because no reasonable person would expect it to fail this way. So, life goes on.</i></span>Unknown[email protected]17tag:blogger.com,1999:blog-383549007228220941.post-22613143794318834052014-09-02T18:19:00.000-07:002014-09-02T18:22:01.009-07:00CVE-2014-1564: Uninitialized memory with truncated images in FirefoxThe recent release of Firefox 32 fixes another interesting image parsing issue found by <a href='http://code.google.com/p/american-fuzzy-lop'>american fuzzy lop</a>: following a refactoring of memory management code, the past few versions of the browser ended up using uninitialized memory for certain types of truncated images, which is easily measurable with a simple <i>&lt;canvas&gt; + toDataURL()</i> harness that examines all the fuzzer-generated test cases. <p></p> In general, problems like that may leak secrets across web origins, or more prosaically, may help attackers bypass security measures such as ASLR. For a slightly more detailed discussion, check out <a href='http://seclists.org/fulldisclosure/2013/Nov/83'>this post</a>. <p></p> Here's a short proof-of-concept that should work if you haven't updated to 32 yet: <ul> <li> <a href='http://lcamtuf.coredump.cx/ffgif/'>http://lcamtuf.coredump.cx/ffgif/</a> </ul> This is tracked as CVE-2014-1564, Mozilla bug <a href='https://bugzilla.mozilla.org/show_bug.cgi?id=1045977'>1045977</a>. Several more should be coming soon. Unknown[email protected]0tag:blogger.com,1999:blog-383549007228220941.post-5783324326777554422014-08-08T12:42:00.001-07:002014-09-11T23:06:15.815-07:00Binary fuzzing strategies: what works, what doesn'tSuccessful fuzzers live and die by their fuzzing strategies. If the changes made to the input file are too conservative, the fuzzer will achieve very limited coverage. If the tweaks are too aggressive, they will cause most inputs to fail parsing at a very early stage, wasting CPU cycles and spewing out messy test cases that are difficult to investigate and troubleshoot. <p></p> Designing the mutation engine for a new fuzzer has more to do with art than science. But one of the interesting side effects of the design of <a href='http://lcamtuf.blogspot.com/2014/08/a-bit-more-about-american-fuzzy-lop.html'>american fuzzy lop</a> is that it provides a rare feedback loop: you can carefully measure what types of changes to the input file actually result in the discovery of new branches in the code, and which ones just waste your time or money. <p></p> This data is particularly easy to read because the fuzzer also approaches every new input file by going through a series of progressively more complex, but exhaustive and deterministic fuzzing strategies - say, sequential bit flips and simple arithmetics - before diving into purely random behaviors. The reason for this is the desire to generate the simplest and most elegant test cases first; but the design also provides a very good way to quantify how much value each new strategy brings in to the table - and whether we need it at all. <p></p> The measurements of <i>afl</i> fuzzing efficiency for reasonably-sized test cases are remarkably consistent across a variety of real-world binary formats - anything ranging from image files (JPEG, PNG, GIF, WebP) to archives (gzip, xz, tar) - and because of this, I figured that sharing the data more broadly will be useful to folks who are working on fuzzers of their own. So, let's dive in: <ul> <li><b>Walking bit flips:</b> the first and most rudimentary strategy employed by <i>afl</i> involves performing sequential, ordered bit flips. The stepover is always one bit; the number of bits flipped in a row varies from one to four. Across a large and diverse corpus of input files, the observed yields are: <p></p> <ul> <li>Flipping a single bit: ~70 new paths per one million generated inputs, <li>Flipping two bits in a row: ~20 additional paths per million generated inputs, <li>Flipping four bits in a row: ~10 additional paths per million inputs. </ul> <p></p> (Note that the counts for every subsequent pass include only the paths that could <b>not</b> have been discovered by the preceding strategy.) <p></p> Of course, the strategy is relatively expensive, with each pass requiring eight <i>execve()</i> per every byte of the input file. With the returns are diminishing rapidly, <i>afl</i> stops after these three passes - and switches to a second, less expensive strategy past that point. <p></p> <li><b>Walking byte flips:</b> a natural extension of walking bit flip approach, this method relies on 8-, 16-, or 32-bit wide bitflips with a constant stepover of one byte. This strategy discovers around ~30 additional paths per million inputs, on top of what could have been triggered with shorter bit flips. <p></p> It should be fairly obvious that each pass takes approximately one <i>execve()</i> call per one byte of the input file, making it surprisingly cheap, but also limiting its potential yields in absolute terms. <p></p> <li><b>Simple arithmetics:</b> to trigger more complex conditions in a deterministic fashion, the third stage employed by <i>afl</i> attempts to subtly increment or decrement existing integer values in the input file; this is done with a stepover of one byte. The experimentally chosen range for the operation is -35 to +35; past these bounds, fuzzing yields drop dramatically. In particular, the popular option of sequentially trying every single value for each byte (equivalent to arithmetics in the range of -128 to +127) helps very little and is skipped by <i>afl</i>. <p></p> When it comes to the implementation, the stage consists of three separate operations. First, the fuzzer attempts to perform subtraction and addition on individual bytes. With this out of the way, the second pass involves looking at 16-bit values, using both endians - but incrementing or decrementing them only if the operation would have also affected the most significant byte (otherwise, the operation would simply duplicate the results of the 8-bit pass). The final stage follows the same logic, but for 32-bit integers. <p></p> The yields for this method vary depending on the format - ranging from ~2 additional paths per million in JPEG to ~8 per million in xz. The cost is relatively high, averaging around 20 <i>execve()</i> calls per one byte of the input file - but can be significantly improved with only a modest impact on path coverage by sticking to +/- 16. <p></p> <li><b>Known integers:</b> the last deterministic approach employed by <i>afl</i> relies on a hardcoded set of integers chosen for their demonstrably elevated likelihood of triggering edge conditions in typical code (e.g., -1, 256, 1024, MAX_INT-1, MAX_INT). The fuzzer uses a stepover of one byte to sequentially overwrite existing data in the input file with one of the approximately two dozen "interesting" values, using both endians (the writes are 8-, 16-, and 32-bit wide). <p></p> The yields for this stage are between 2 and 5 additional paths per one million tries; the average cost is roughly 30 <i>execve()</i> calls per one byte of input file. <p></p> <li><b>Stacked tweaks:</b> with deterministic strategies exhausted for a particular input file, the fuzzer continues with a never-ending loop of randomized operations that consist of a stacked sequence of: <p></p> <ul> <li> Single-bit flips, <li> Attempts to set "interesting" bytes, words, or dwords (both endians), <li> Addition or subtraction of small integers to bytes, words, or dwords (both endians), <li> Completely random single-byte sets, <li> Block deletion, <li> Block duplication via overwrite or insertion, <li> Block memset. </ul> <p></p> Based on a fair amount of testing, the optimal execution path yields appear to be achieved when the probability of each operation is roughly the same; the number of stacked operations is chosen as a power-of-two between 1 and 64; and the block size for block operations is capped at around 1 kB. <p></p> The absolute yield for this stage is typically comparable or higher than the total number of execution paths discovered by all deterministic stages earlier on. <p></p> <li><b>Test case splicing:</b> this is a last-resort strategy that involves taking two distinct input files from the queue that differ in at least two locations; and splicing them at a random location in the middle before sending this transient input file through a short run of the "stacked tweaks" algorithm. This strategy usually discovers around 20% additional execution paths that are unlikely to trigger using the previous operation alone. <p></p> (Of course, this method requires a good, varied corpus of input files to begin with; <i>afl</i> generates one automatically, but for other tools, you may have to construct it manually.) <p></p> </ul> As you can see, deterministic block operations (duplication, splicing) are not attempted in an exhaustive fashion; this is because they generally require quadratic time (or worse) - so while their yields may be good for very short inputs, they degrade very quickly. <p></p> Well, that's it! If you ever decide to try out afl, you can watch these and <a href='https://code.google.com/p/american-fuzzy-lop/wiki/StatusScreen'>other cool stats</a> on your screen in real time. Unknown[email protected]3tag:blogger.com,1999:blog-383549007228220941.post-54434899239895970232014-08-04T18:46:00.002-07:002014-10-14T12:19:27.039-07:00A bit more about american fuzzy lop<a href='http://lcamtuf.coredump.cx/afl_gzip.png'><img src='http://lcamtuf.coredump.cx/afl_gzip_small.png'></a><p></p> Fuzzing is one of the most powerful strategies for identifying security issues in real-world software. Unfortunately, it also offers fairly shallow coverage: it is impractical to exhaustively cycle through all possible inputs, so even something as simple as setting three separate bytes to a specific value to reach a chunk of unsafe code can be an insurmountable obstacle to a typical fuzzer. <p></p> There have been numerous attempts to solve this problem by augmenting the process with additional information about the behavior of the tested code. These techniques can be divided into three broad groups: <ul> <li> <b>Simple coverage maximization.</b> This approach boils down to trying to isolate initial test cases that offer diverse code coverage in the targeted application - and them fuzzing them using conventional techniques.<p></p> <li> <b>Control flow analysis.</b> A more sophisticated technique that leverages instrumented binaries to focus the fuzzing efforts on mutations that generate distinctive sequences of conditional branches within the instrumented binary.<p></p> <li> <b>Static analysis.</b> An approach that attempts to reason about potentially interesting states within the tested program and then make educated guesses about the input values that could possibly trigger them. </ul> The first technique is surprisingly powerful when used to pre-select initial test cases from a massive corpus of valid data - say, the result of a large-scale web crawl. Unfortunately, coverage measurements provide only a very simplistic view of the internal state of the program, making them less suited for creatively guiding the fuzzing process later on. <p></p> The latter two techniques are extremely promising in experimental settings. That said, in real-world applications, they are not only very slow, but frequently lead to irreducible complexity: most of the high-value targets will have a vast number of internal states and possible execution paths, and deciding which ones are interesting and substantially different from the rest is an extremely difficult challenge that, if not solved, usually causes the "smart" fuzzer to perform no better than a traditional one. <p></p> <a href='http://code.google.com/p/american-fuzzy-lop'>American fuzzy lop</a> tries to find a reasonable middle ground between sophistication and practical utility. In essence, it's a fuzzer that relies on a form of edge coverage measurements to detect subtle, local-scale changes to program control flow without having to perform complex global-scale comparisons between series of long and winding execution traces - a common failure point for similar tools. <p></p> In almost-plain English, the fuzzer does this by instrumenting every effective line of C or C++ code (or any other GCC-supported language) to record a tuple in the following format: <p></p> <code style="margin-left: 8ex">[ID of current code location], [ID of previously-executed code location]</code> <p></p> The ordering information for tuples is discarded; the primary signal used by the fuzzer is the appearance of a previously-unseen tuple in the output dataset; this is also coupled with coarse magnitude count for tuple hit rate. This method combines the self-limiting nature of simple coverage measurements with the sensitivity of control flow analysis. It detects both explicit conditional branches, and indirect variations in the behavior of the tested app. <p></p> The output from this instrumentation is used as a part of a simple, vaguely "genetic" algorithm: <ol> <li> Load user-supplied initial test cases into the queue,<p></p> <li> Take input file from the queue,<p></p> <li> Repeatedly mutate the file using a balanced variety of traditional fuzzing strategies (see later),<p></p> <li> If any of the generated mutations resulted in a new tuple being recorded by the instrumentation, add mutated output as a new entry in the queue.<p></p> <li> Go to 2. </ol> The discovered test cases are also periodically culled to eliminate ones that have been made obsolete by more inclusive finds discovered later in the fuzzing process. Because of this, the fuzzer is useful not only for identifying crashes, but is exceptionally effective at turning a single valid input file into a reasonably-sized corpus of interesting test cases that can be manually investigated for non-crashing problems, handed over to <i>valgrind</i>, or used to stress-test applications that are harder to instrument or too slow to fuzz efficiently. In particular, it can be extremely useful for generating small test sets that may be programatically or manually examined for anomalies in a browser environment. <p></p> (For a quick partial demo, <a href='http://lcamtuf.coredump.cx/afl_demo/'>click here</a>.) <p></p> Of course, there are countless "smart" fuzzer designs that look good on paper, but fail in real-world applications. I tried to make sure that this is not the case here: for example, afl can easily tackle security-relevant and tough targets such as <i>gzip</i>, <i>xz</i>, <i>lzo</i>, <i>libjpeg</i>, <i>libpng</i>, <i>giflib</i>, <i>libtiff</i>, or <i>webp</i> - all with absolutely no fine-tuning and while running at blazing speeds. The control flow information is also extremely useful for accurately de-duping crashes, so the tool does that for you. <p></p> In fact, I spent some time running it on a single machine against <i>libjpeg</i>, <i>giflib</i>, and <i>libpng</i> - some of the most robust best-tested image parsing libraries out there. So far, the tool found: <ul> <li> <b><a href='http://seclists.org/fulldisclosure/2013/Nov/83'>CVE-2013-6629</a>:</b> JPEG SOS component uninitialized memory disclosure in <i>jpeg6b</i> and <i>libjpeg-turbo</i>,<p></p> <li> <b><a href='http://seclists.org/fulldisclosure/2013/Nov/83'>CVE-2013-6630</a>:</b> JPEG DHT uninitialized memory disclosure in <i>libjpeg-turbo</i>,<p></p> <li> <b><a href='http://lcamtuf.blogspot.com/2014/10/two-more-browser-memory-disclosure-bugs.html'>MSRC 0380191</a>:</b> A separate JPEG DHT uninitialized memory disclosure in Internet Explorer,<p></p> <li> <b><a href='http://lcamtuf.blogspot.com/2014/09/cve-2014-1564-uninitialized-memory-when.html'>CVE-2014-1564</a>:</b> Uninitialized memory disclosure via GIF images in Firefox,<p></p> <li> <b><a href='https://www.mozilla.org/security/announce/2014/mfsa2014-78.html'>CVE-2014-1580</a>:</b> Uninitialized memory disclosure via &lt;canvas&gt; in Firefox,<p></p> <li> <b><a href='https://code.google.com/p/chromium/issues/detail?id=398235'>Chromium bug #398235</a>, <a href='https://bugzilla.mozilla.org/show_bug.cgi?id=1050342'>Mozilla bug #1050342</a>:</b> Probable library-related JPEG security issues in Chrome and Firefox (pending),<p></p> <li> PNG <a href='https://twitter.com/taviso/status/484032144801398784'>zlib API misuse bug</a> in MSIE (DoS-only),<p></p> <li> Several browser-crashing images in WebKit browsers (DoS-only). </ul> More is probably to come. In other words, you should probably <a href='http://code.google.com/p/american-fuzzy-lop'>try it out</a>. The most significant limitation today is that the current fuzzing strategies are optimized for binary files; the fuzzer does: <ul> <li> Walking bitflips - 1, 2, and 4 bits,<p></p> <li> Walking byte flips - 1, 2, and 4 bytes,<p></p> <li> Walking addition and subtraction of small integers - byte, word, dword (both endians),<p></p> <li> Walking insertion of interesting integers (-1, MAX_INT, etc) - byte, word, dword (both endians),<p></p> <li> Random stacked flips, arithmetics, block cloning, insertion, deletion, etc,<p></p> <li> Random splicing of synthetized test cases - pretty unique! </ul> All these strategies have been specifically selected for an optimal balance between fuzzing cost and yields measured in terms of the number of discovered execution paths with binary formats; for highly-redundant text-based formats such as HTML or XML, syntax-aware strategies (template- or ABNF-based) will obviously yield better results. Plugging them into AFL would not be hard, but requires work.Unknown[email protected]0tag:blogger.com,1999:blog-383549007228220941.post-67107035919112958262014-06-22T20:04:00.000-07:002014-06-22T20:04:42.092-07:00Boolean algebra with CSS (when you can only set colors)Depending on how you look at it, CSS can be considered <a href='http://eli.fox-epste.in/rule110-full.html'>Turing-complete</a>. But in one privacy-relevant setting - when styling <i>:visited</i> links - the set of CSS directives you can use is extremely limited, effectively letting you control not much more than the color of the text nested between <i>&lt;a href=...&gt;</i> and <i>&lt;/a&gt;</i>. Can you perform any computations with that? <p></p> Well, as it turns out, you can - in a way. Check out <a href='http://lcamtuf.coredump.cx/css_algebra/'>this short write-up</a> for a discussion on how to implement Boolean algebra by exploiting an interesting implementation-level artifact of CSS blending to steal your browsing history a bit more efficiently than before. <p></p> Vulnerability logo and vanity domain forthcoming - stay tuned. Unknown[email protected]0