Author vstinner
Recipients vstinner
Date 2020-01-30.15:11:28
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1580397089.41.0.564267118679.issue39503@roundup.psfhosted.org>
In-reply-to
Content
Copy of an email received on the Python Security Response team, 9 days ago. I consider that it's not worth it to have an embargo on this vulnerability, so I make it public.

Hi there,

I believe I've found a denial-of-service (DoS) bug in
urllib.request.AbstractBasicAuthHandler. To start, I'm operating on some
background information from this document: HTTP authentication
<https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication>. The bug
itself is a ReDoS <https://www.regular-expressions.info/redos.html> bug
causing catastrophic backtracking. To reproduce the issue we can use the
following code:

from urllib.request import AbstractBasicAuthHandler
auth_handler = AbstractBasicAuthHandler()
auth_handler.http_error_auth_reqed(
    'www-authenticate',
    'unused',
    'unused',
    {
        'www-authenticate': 'Basic ' + ',' * 64 + ' ' + 'foo' + ' ' +
'realm'
    }
)

The issue itself is in the following regular expression:

rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+'
                'realm=(["\']?)([^"\']*)\\2', re.I)

In particular, the (?:.*,)* portion. Since "." and "," overlap and there
are nested quantifiers we can cause catastrophic backtracking by repeating
a comma. Note that since AbstractBasicAuthHandler is vulnerable, then both
HTTPBasicAuthHandler and ProxyBasicAuthHandler are as well because they
call http_error_auth_reqed. Building from the HTTP authentication document
above, this means a server can send a specially crafted header along with
an HTTP 401 or HTTP 407 and cause a DoS on the client.

I won't speculate on the severity of the issue too much - you will surely
understand the impact better than I will. Although, the fact that this is
client-side as opposed to server-side appears to reduce the severity,
however the fact that it's a security-sensitive context (HTTP
authentication) may raise the severity.

One possible fix would be changing the rx expression to the following:

rx = re.compile('(?:[^,]*,)*[ \t]*([^ \t]+)[ \t]+'
                'realm=(["\']?)([^"\']*)\\2', re.I)

This removes the character overlap in the nested quantifier and thus
negates the catastrophic backtracking.

Let me know if you have any questions or what the next steps are from here.
Thanks for supporting Python security!

-- 
Matt Schwager
History
Date User Action Args
2020-01-30 15:11:29vstinnersetrecipients: + vstinner
2020-01-30 15:11:29vstinnersetmessageid: <1580397089.41.0.564267118679.issue39503@roundup.psfhosted.org>
2020-01-30 15:11:29vstinnerlinkissue39503 messages
2020-01-30 15:11:28vstinnercreate