-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
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
CVE-2021-3737: urllib http client possible infinite loop on a 100 Continue response #88188
Comments
if a client request a http/https/ftp service which is controlled by attacker, attacker can make this client hang forever, event client has set "timeout" argument. maybe this client also will consume more and more memory. i does not test on this conclusion. client.py
evil_server.py
|
Added a possible PR. Review will be appreicated. |
Looks like it is caused by the httplib not limiting total header size after receiving 100. Added a counter for that to be same size as _MAXLINE=65536. |
The bug: Our http client can get stuck infinitely reading len(line) < 64k lines after receiving a '100 Continue' http response. So yes, this could lead to our client being a bandwidth sink for anyone in control of a server. Clear issue: That's a denial of network bandwidth and the denial of service in terms of CPU needed to process read and skip such lines. The infinite lines are size bounded and are not buffered so there is no memory based DoS. Maybe issue: If a the underlying socket has a timeout set on it, it can be used to prevent the timeout from triggering by sending a line more often than the timeout. this is a denial of service by making a http client connection that an author may have assumed would timeout based on their socket.setdefaulttimeout() settings hang forever. I expect there are plenty of other ways to accomplish the latter in our http client code though. Ex: A regular response with a huge content length where one byte is transmitted occasionally could also effectively accomplish that. The stdlib http stack doesn't have its own overall http transaction timeout as a feature. |
Thanks guangli dong (leveryd)! This is in and the 3.10-3.6 PRs should automerge (thru 3.9) after the CI runs, or be merged by the release managers (3.6-3.8). |
can you assign "cve" for this security bug? i will review the patch later. |
http.server is out of scope for CVEs. The module is not designed for security-sensitive usage and explicitly documented as insecure and not suitable for production use: https://docs.python.org/3/library/http.server.html#module-http.server
|
If anyone wants a CVE for it, that's up to them. This bug is in the CPython http.client module which is what urllib uses for http/https. I'd rate it low severity. A malicious server can hold a http connection from this library open as a network traffic sink. There are other ways to do that. ex: Just use omit a content-length header in a server response and start streaming an infinite response. The difference in this case being that since the data is thrown away, it isn't going to result in memory exhaustion and kill the unfortunate process as trying to read an infinite response would. That's the primary DoS potential from my point of view. |
@gregory P. Smith yes, i agree that there are many other ways to make "urllib" or "httplib" such http client hang, because "timeout" is not global read timeout, this "timeout" has effects when every "read socket" operation. why you think it will not result in memory exhaustion? the "hlist" list will not be more and more larger? i use "top" command to observe, and find the "client.py" process's memory is more and more larger slowly.
the last, would you mind remove "100 Continue" in this bug title? i think it will maybe make others misunderstand that this bug only occur when response status code is "100". |
httplib.py is a Python 2 concept. Python 2 is end of life. bugs.python.org no longer tracks issues with its code. I don't doubt that Python 2.7 has bugs. As a matter of policy, we don't care - https://www.python.org/doc/sunset-python-2/. Python 3.6 as that is the oldest branch still open for security fixes. The PRs associated with this issue fixed a codepath in Python 3 that only happened after a '100' response. That codepath did not accumulate headers:
CONTINUE = 100; meaning that loop only runs after receiving what appears to be a 100 continue response. And it does not accumulate data. There is no |
The test added for this bug is insufficient to verify the fix. If I revert the Lib/http/client.py change, the test still passes. This is because a subclass of client.HTTPException is still raised. If I add an explicit begin() call to trigger the exception, then without the fix I get: File "/tmp/cpython/Lib/test/test_httplib.py", line 1189, in test_overflowing_header_limit_after_100 With the fix, I get (correctly): test test_httplib failed -- Traceback (most recent call last):
File "/tmp/cpython/Lib/test/test_httplib.py", line 1189, in test_overflowing_header_limit_after_100
resp.begin()
File "/tmp/cpython/Lib/http/client.py", line 321, in begin
skipped_headers = _read_headers(self.fp)
File "/tmp/cpython/Lib/http/client.py", line 218, in _read_headers
raise HTTPException("got more than %d headers" % _MAXHEADERS)
http.client.HTTPException: got more than 100 headers However, the test considers both exceptions to match. |
Great catch! The new PR should address that. |
Is there a CVE for this? |
Matej Cepl: "Is there a CVE for this?" Yes, CVE-2021-3737 was assigned to this issue. |
I created https://python-security.readthedocs.io/vuln/urllib-100-continue-loop.html to track the issue. |
I'm not sure why the fix in the main branch was not listed here: commit 47895e3
|
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: