bpo-39503: CVE-2020-8492: Fix AbstractBasicAuthHandler#18284
Conversation
Sorry, something went wrong.
|
This fix looks good to me! |
Sorry, something went wrong.
|
Would be nice to add a test. |
Sorry, something went wrong.
|
Just a heads up, CVE-2020-8492 has been created. I'm not sure how Python CVEs are generally tracked, but it may be useful to include the information on the bug tracker issue 👍 |
Sorry, something went wrong.
|
Not only We can either simplify the regex to prevent the "catastrophic backtracking" or even remove the prefix. UPDATE: Oops, my example was wrong, I fixed it :-) |
Sorry, something went wrong.
It seems to me that the >>> header = 'basic realm="1", x, other realm="2"'
>>> re.search("(?:.*,)*[ \t]*([^ \t]+)[ \t]+", header).group(1)
'other'
>>> re.search("[ \t]*([^ \t]+)[ \t]+", header).group(1)
'basic'
>>> I don't see a way to fix this by just changing the regex while preserving the previous behavior. Then again, corner cases of the previous behavior might be wrong. |
Sorry, something went wrong.
|
I rebased my PR and added more tests. |
Sorry, something went wrong.
|
@serhiy-storchaka: I don't understand if you consider that the fix is wrong or that the fix is not enough (it remains possible to create a denial of service)? |
Sorry, something went wrong.
|
@vstinner your fix helps, but we can do better. It has cubic complexity, my suggestion has quadratic complexity. It is possible to implement an algorithm with linear complexity, but not with such small changes. |
Sorry, something went wrong.
|
I also added some tests and implemented a simpler complexity regex - see master...davidfraser:urllib_basic_auth_regex |
Sorry, something went wrong.
|
It's worth seeing how the results of this regex are actually used Note my comment in f79379c: Note that the original regex was roughly O(2**n) |
Sorry, something went wrong.
|
WWW-Authenticate is badly specified. The RFC doesn't specify if a single HTTP header can contain multiple challenges. I found these resources:
A variant is to have multiple WWW-Authenticate: one challenge per WWW-Authenticate header. By the way, AbstractBasicAuthHandler code contains this interesting comment: Current behavior:
For example, |
Sorry, something went wrong.
Sorry, I misunderstood this proposition. In fact, I proposed something similar except that I missed the "start of the string" (regex I decided to write a way more complex change to not only fix the vulnerability, but also fix the parser since it didn't look possible to fix the regex without changing the behavior. Currently, the code uses the last realm if there are multiple challenges per header. I fixed this behavior to use the realm of the first Basic challenge. I also modified the code to support multiple headers, except of only parsing the first one. |
Sorry, something went wrong.
|
Ok, the PR is now ready for a new round of reviews. I fixed the vulnerability but I also changed the code to parse all WWW-Authenticate HTTP Headers and accept multiple challenges per header. |
Sorry, something went wrong.
The AbstractBasicAuthHandler class of the urllib.request module uses an inefficient regular expression which can be exploited by an attacker to cause a denial of service. Fix the regex to prevent the catastrophic backtracking. Vulnerability reported by Ben Caller and Matt Schwager. AbstractBasicAuthHandler of urllib.request now parses all WWW-Authenticate HTTP headers and accepts multiple challenges per header: use the realm of the first Basic challenge. Co-Authored-By: Serhiy Storchaka <storchaka@gmail.com>
|
Oh, Ben Caller reported the issue at 2019-11-17: https://bugs.python.org/issue38826 |
Sorry, something went wrong.
Thanks, @vstinner - This was a good detection and change. I am reviewing the patch further. |
Sorry, something went wrong.
orsenthil
left a comment
There was a problem hiding this comment.
Hi @vstinner
Thanks for the patch and the change. The entire addition is meaningful and looks good to me.
- The change of regex only the security issue keeps the patch simple.
I only had a question in the tests, but it is not a critical question. I thought, I am missing something by adding of "digest" test case in line 1469, when the multiple headers challenge is covered again in the same test case at line 1499.
LGTM.
Sorry, something went wrong.
The AbstractBasicAuthHandler class of the urllib.request module uses an inefficient regular expression which can be exploited by an attacker to cause a denial of service. Fix the regex to prevent the catastrophic backtracking. Vulnerability reported by Ben Caller and Matt Schwager. AbstractBasicAuthHandler of urllib.request now parses all WWW-Authenticate HTTP headers and accepts multiple challenges per header: use the realm of the first Basic challenge. Co-Authored-By: Serhiy Storchaka <storchaka@gmail.com> (cherry picked from commit 0b297d4) Co-authored-by: Victor Stinner <vstinner@python.org>
⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️Hi! The buildbot s390x SLES 3.x has failed when building commit 0b297d4. What do you need to do:
You can take a look at the buildbot page here: https://buildbot.python.org/all/#builders/6/builds/675 Failed tests:
Failed subtests:
Summary of the results of the build (if available): == Tests result: FAILURE then FAILURE == 404 tests OK. 10 slowest tests:
1 test failed: 15 tests skipped: 1 re-run test: Total duration: 7 min 14 sec Click to see traceback logsTraceback (most recent call last):
File "/home/dje/cpython-buildarea/3.x.edelsohn-sles-z/build/Lib/imaplib.py", line 989, in _command
self.send(data + CRLF)
File "/home/dje/cpython-buildarea/3.x.edelsohn-sles-z/build/Lib/imaplib.py", line 331, in send
self.sock.sendall(data)
File "/home/dje/cpython-buildarea/3.x.edelsohn-sles-z/build/Lib/ssl.py", line 1204, in sendall
v = self.send(byte_view[count:])
File "/home/dje/cpython-buildarea/3.x.edelsohn-sles-z/build/Lib/ssl.py", line 1173, in send
return self._sslobj.write(data)
BrokenPipeError: [Errno 32] Broken pipe
Traceback (most recent call last):
File "/home/dje/cpython-buildarea/3.x.edelsohn-sles-z/build/Lib/test/test_imaplib.py", line 951, in tearDown
self.server.logout()
File "/home/dje/cpython-buildarea/3.x.edelsohn-sles-z/build/Lib/imaplib.py", line 641, in logout
typ, dat = self._simple_command('LOGOUT')
File "/home/dje/cpython-buildarea/3.x.edelsohn-sles-z/build/Lib/imaplib.py", line 1213, in _simple_command
return self._command_complete(name, self._command(name, *args))
File "/home/dje/cpython-buildarea/3.x.edelsohn-sles-z/build/Lib/imaplib.py", line 991, in _command
raise self.abort('socket error: %s' % val)
imaplib.IMAP4.abort: socket error: [Errno 32] Broken pipe
|
Sorry, something went wrong.
|
Thanks @vstinner for the PR 🌮🎉.. I'm working now to backport this PR to: 3.8. |
Sorry, something went wrong.
|
Thanks @vstinner for the PR 🌮🎉.. I'm working now to backport this PR to: 3.7. |
Sorry, something went wrong.
The AbstractBasicAuthHandler class of the urllib.request module uses an inefficient regular expression which can be exploited by an attacker to cause a denial of service. Fix the regex to prevent the catastrophic backtracking. Vulnerability reported by Ben Caller and Matt Schwager. AbstractBasicAuthHandler of urllib.request now parses all WWW-Authenticate HTTP headers and accepts multiple challenges per header: use the realm of the first Basic challenge. Co-Authored-By: Serhiy Storchaka <storchaka@gmail.com> (cherry picked from commit 0b297d4) Co-authored-by: Victor Stinner <vstinner@python.org>
…-19296) The AbstractBasicAuthHandler class of the urllib.request module uses an inefficient regular expression which can be exploited by an attacker to cause a denial of service. Fix the regex to prevent the catastrophic backtracking. Vulnerability reported by Ben Caller and Matt Schwager. AbstractBasicAuthHandler of urllib.request now parses all WWW-Authenticate HTTP headers and accepts multiple challenges per header: use the realm of the first Basic challenge. Co-Authored-By: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Victor Stinner <vstinner@python.org> (cherry picked from commit 0b297d4)
…-19297) The AbstractBasicAuthHandler class of the urllib.request module uses an inefficient regular expression which can be exploited by an attacker to cause a denial of service. Fix the regex to prevent the catastrophic backtracking. Vulnerability reported by Ben Caller and Matt Schwager. AbstractBasicAuthHandler of urllib.request now parses all WWW-Authenticate HTTP headers and accepts multiple challenges per header: use the realm of the first Basic challenge. Co-Authored-By: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Victor Stinner <vstinner@python.org> (cherry picked from commit 0b297d4)
…-19304) The AbstractBasicAuthHandler class of the urllib.request module uses an inefficient regular expression which can be exploited by an attacker to cause a denial of service. Fix the regex to prevent the catastrophic backtracking. Vulnerability reported by Ben Caller and Matt Schwager. AbstractBasicAuthHandler of urllib.request now parses all WWW-Authenticate HTTP headers and accepts multiple challenges per header: use the realm of the first Basic challenge. Co-Authored-By: Serhiy Storchaka <storchaka@gmail.com> (cherry picked from commit 0b297d4)
…9305) The AbstractBasicAuthHandler class of the urllib.request module uses an inefficient regular expression which can be exploited by an attacker to cause a denial of service. Fix the regex to prevent the catastrophic backtracking. Vulnerability reported by Ben Caller and Matt Schwager. AbstractBasicAuthHandler of urllib.request now parses all WWW-Authenticate HTTP headers and accepts multiple challenges per header: use the realm of the first Basic challenge.
The AbstractBasicAuthHandler class of the urllib.request module uses
an inefficient regular expression which can be exploited by an
attacker to cause a denial of service. Fix the regex to prevent the
catastrophic backtracking.
Vulnerability reported by Matt Schwager.
https://bugs.python.org/issue39503