Source: Abstract Modern exploit mitigations draw attackers into a game of diminishing marginal returns. With each additional mitigation added, a subset of software bugs become unexploitable, and others become difficult to exploit, requiring application or even bug-specific knowledge that cannot be reused. The practical effect of exploit mitigations against any given bug or class of bugs is the subject of great debate amongst security researchers. Despite mitigations, skilled and determined attackers alike remain undeterred. They cope by finding more bugs, and by crafting increasingly complex exploit chains. Attackers treat these exploits as closely-guarded, increasingly valuable secrets, and it's rare to see publicly-available full-fledged exploit chains. This visibility problem contributes to an attacker's advantage in the short term, but hinders broader innovation. In this blog post, I describe an exploit chain for several bugs I discovered in CUPS, an open-source printing suite. I start by analyzing a relatively-subtle bug in CUPS string handling (CVE-2015-1158), an exploit primitive. I discuss key design and implementation choices that contributed to this bug. I then discuss how to build an exploit using the primitive. Next, I describe a second implementation error (CVE-2015-1159) that compounds the effect of the first, exposing otherwise unreachable instances of CUPS. Finally, I discuss the specific features and configuration options of CUPS that either helped or hindered exploitation. By publishing this analysis, I hope to encourage transparent discourse on the state of exploits and mitigations, and inspire other researchers to do the same. Summary Cupsd uses reference-counted strings with global scope. When parsing a print job request, cupsd can be forced to over-decrement the reference count for a string from the request. As a result, an attacker can prematurely free an arbitrary string of global scope. I use this to dismantle ACL's protecting privileged operations, upload a replacement configuration file, then run arbitrary code. The reference count over-decrement is exploitable in default configurations, and does not require any special permissions other than the basic ability to print. A cross-site scripting bug in the CUPS templating engine allows this bug to be exploited when a user browses the web. The XSS is reachable in the default configuration for Linux instances of CUPS, and allows an attacker to bypass default configuration settings that bind the CUPS scheduler to the 'localhost' or loopback interface. Exploitation is near-deterministic, and does not require complex memory-corruption 'acrobatics'. Reliability is not affected by traditional exploit mitigations. Background Improper Teardown - Reference Count Over-Decrement (CVE-2015-1158) When freeing localized multi-value attributes, the reference count on the language string is over-decremented when creating a print job whose 'job-originating-host-name' attribute has more than one value. In 'add_job()', cupsd incorrectly frees the 'language' field for all strings in a group, instead of using 'ipp_free_values()'. scheduler/ipp.c:1626: /* * Free old strings… ← Even 'old' strings need to be freed. */ for (i = 0; i < attr->num_values; i ++) { _cupsStrFree(attr->values[i].string.text); attr->values[i].string.text = NULL; if (attr->values[i].string.language) ← for all values in an attribute { _cupsStrFree(attr->values[i].string.language); ← free the 'language' string attr->values[i].string.language = NULL; } } In this case, 'language' field comes from the value of the 'attributes-natural-language' attribute in the request. To specifically target a string and free it, we send a 'IPP_CREATE_JOB' or 'IPP_PRINT_JOB' request with a multi-value 'job-originating-host-name' attribute. The number of 'job-originating-host-name' values controls how many times the reference count is decremented. For a 10-value attribute, the reference count for 'language' is increased once, but decremented 10 times. The over-decrement prematurely frees the heap block for the target string. The actual block address will be quickly re-used by subsequent allocations. Dangling pointers to the block remain, but the content they point to changes when blocks are freed or reused. This is the basic exploit primitive upon which we build. A Reflected XSS in the Web Interface (CVE-2015-1159) The template engine is only vaguely context-aware, and only supports HTML. Template parsing and variable substitution and escaping are handled in 'cgi_copy()'. The template engine has 2 special cases for 'href' attributes from HTML links. The first case 'cgi_puturi()' is unused in current templates, but the second case ends up being interesting. The code is found in 'cgi_puts()', and escapes the following reserved HTML characters: <>"'& These are replaced with their HTML entity equivalents ('<' etc...). The function contains a curious special case to deal with HTML links in variable values. Here is a code snippet, from cgi-bin/template.c:650: if (*s == '<') { /* * Pass and , otherwise quote it... */ if (!_cups_strncasecmp(s, "", out); } For variable values containing 'All Documents

In this case, the CGI argument 'QUERY' is already contained inside a 'href' attribute of a link. If 'QUERY' starts with '