GeezerVison is showing github.com — [security] CVE-2021-28861: http.server: Open Redirection if the URL path starts with // · Issue #87389 · python/cpython
[security] CVE-2021-28861: http.server: Open Redirection if the URL path starts with // #87389Description
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:
assignee = None
closed_at = None
created_at = <Date 2021-02-14.11:42:36.898>
labels = ['type-security', 'deferred-blocker', '3.8', '3.9', '3.10', '3.11', '3.7', 'library']
title = '[security] http.server: Open Redirection if the URL path starts with //'
updated_at = <Date 2021-05-23.08:10:57.234>
user = 'https://github.com/hamzaavvan'
bugs.python.org fields:
activity = <Date 2021-05-23.08:10:57.234>
actor = 'hamzaavvan'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Library (Lib)']
creation = <Date 2021-02-14.11:42:36.898>
creator = 'hamzaavvan'
dependencies = []
files = ['49808']
hgrepos = ['404']
issue_num = 43223
keywords = ['patch']
message_count = 5.0
messages = ['386945', '387193', '387284', '390047', '394193']
nosy_count = 9.0
nosy_names = ['paul.moore', 'vstinner', 'christian.heimes', 'tim.golden', 'ned.deily', 'lukasz.langa', 'zach.ware', 'steve.dower', 'hamzaavvan']
pr_nums = ['24848']
priority = 'deferred blocker'
resolution = None
stage = 'patch review'
status = 'open'
superseder = None
type = 'security'
url = 'https://bugs.python.org/issue43223'
versions = ['Python 3.6', 'Python 3.7', 'Python 3.8', 'Python 3.9', 'Python 3.10', 'Python 3.11']
Linked PRs
Activityhamzaavvan commented on Feb 14, 2021 MannequinAuthor More actions hamzaavvan changed the title [-]Open Redirection In Python 3.7 & 3.8[/-] [+][SECURITY] Open Redirection In Python 3.7 & 3.8[/+] on Feb 15, 2021hamzaavvan changed the title [-]Open Redirection In Python 3.7 & 3.8[/-] [+][SECURITY] Open Redirection In Python 3.7 & 3.8[/+] on Feb 15, 2021vstinner commented on Feb 17, 2021 I can only reproduce the issue if the current directory (directory used by the HTTP server, see --directory command line option) contains a .ssh/ subdirectory.
The problem is that the HTTP Header Location starts with "//domain/" and such URL is interpreted as an absolute URL of a new domain name ("domain"), rather than a relative path of the same domain ("localhost").
Maybe we should simply strip all additional leading slashes to only keep one. Replace "//path" or "/////path" with "/path" for example.
---
By the way, http.server uses urllib.parse.urlsplit() on the request URL without passing its own domain, and urllib.parse.urlsplit() interprets "//attacker.com/path" as if attacker.com is a host with no scheme:
>>> urllib.parse.urlsplit('//attacker.com/path')
SplitResult(scheme='', netloc='attacker.com', path='/path', query='', fragment='')
Maybe parse_qs() should be used instead? Or we should reinject the server domain and port number? I am not sure that it's an issue in practice.
SimpleHTTPRequestHandler.translate_path('//attacker.com/..%2f..%2f..%2f..%2f..%2f../.ssh') returns os.path.join(self.directory, ".ssh"). I don't think that it's an issue, it sounds like the expected behavior. We don't attempt to reject ".." in URL.
---
To reproduce the issue, I used two terminals.
Terminal 1:
$ python3.8 -V
Python 3.8.7
$ python3.8 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
127.0.0.1 - - [15/Feb/2021 09:18:20] "GET
//attacker.com/..%2f..%2f..%2f..%2f..%2f../.ssh HTTP/1.1" 301 -
Terminal 2:
$ wget 'http://127.0.0.1:8000//attacker.com/..%2f..%2f..%2f..%2f..%2f../.ssh'
(...)
HTTP request sent, awaiting response... 301 Moved Permanently
Location: //attacker.com/..%2f..%2f..%2f..%2f..%2f../.ssh/ [following]
--2021-02-15 09:18:20-- http://attacker.com/..%2f..%2f..%2f..%2f..%2f../.ssh/
Resolving attacker.com (attacker.com)... 45.88.202.115
Connecting to attacker.com (attacker.com)|45.88.202.115|:80... connected.
(...)
wget is redirected and connects to attacker.com.
The HTTP redirection comes from Lib/http/server.py:
def send_head(self):
path = self.translate_path(self.path)
f = None
if os.path.isdir(path):
parts = urllib.parse.urlsplit(self.path)
if not parts.path.endswith('/'):
# redirect browser - doing basically what apache does
self.send_response(HTTPStatus.MOVED_PERMANENTLY)
new_parts = (parts[0], parts[1], parts[2] + '/',
parts[3], parts[4])
new_url = urllib.parse.urlunsplit(new_parts)
self.send_header("Location", new_url)
self.end_headers()
return None
...
...
The problem is that the "Location" header starts with "//". gpshead commented on Jun 21, 2022 fixed in main, 3.11, and 3.11. the remaining branches are up to the release managers. thanks! ngie-eign commented on Oct 11, 2022 For the record, this reproduces on python 2.7 (I used wget --debug to confirm that the Location field was modified). I suspect that this also reproduces on python version <3.7.
Just a note for others who might be supporting python versions <3.7 in OS distributions. vstinner commented on Oct 12, 2022 changed the title [-][security] http.server: Open Redirection if the URL path starts with //[/-] [+][security] CVE-2021-28861: http.server: Open Redirection if the URL path starts with //[/+] on Oct 12, 2022vstinner commented on Oct 12, 2022
MetadataMetadataStatusShow more project fields
DevelopmentNo branches or pull requestsIssue actions
|