-
-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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
bpo-29606: urllib throwing an exception on any URLs that contain one of '\r\n' for the FTP protocol. #1216
Conversation
@corona10, thanks for your PR! By analyzing the history of the files in this pull request, we identified @orsenthil, @ncoghlan and @Yhg1s to be potential reviewers. |
004805b
to
b035bed
Compare
@orenmn |
I am sorry, but I am quite busy these days. Also, I am not familiar with the implementation of urllib.
|
@orenmn Please take a look. One more thing, If this patch is landed, I think that backporting patches are might be needed for Python 3.x. @ncoghlan |
As I mentioned, I am quite busy these days, and not familiar with the relevant code, so I don't think I can help with this patch any more.. |
@corona10 - I will review this one. |
@orsenthil Great! |
Sorry, closing was a mistake. |
12439c6
to
6eb73f0
Compare
@orsenthil I rebase it. PTAL |
@orsenthil If you have a time can you take a look? |
@corona10 - I did, but give me some time. I am in travel, and I will definitely act on this soon. |
399bfd0
to
fa97d08
Compare
Hi Everyone, I'm the guy that worked out how to exploit these bugs with firewalls. I just figured I would chime in and provide some opinions. For one, any URL parsing code that is not FTP-specific should not have input validation checks added. After all, other protocols might be able to handle CR/LF/NUL just fine through an appropriate encoding mechanism. I don't think explicit checks just after decoding are necessarily the best place for this (though I don't see a way to exploit the issue with the proposed patch). In my mind, the fact that CR/LF are an FTP-specific issue and should be dealt with right before FTP commands are dropped on the wire. For the sake of having more complete test cases, please also consider adding
Finally, I would encourage you to reject any NUL bytes in HTH, |
I may need to revise my advice here... @giampaolo pointed out that RFC-2640 provides a mechanism for escaping newline sequences in FTP. It's not yet clear if this is the best approach (even though it may be the most correct approach), since many FTP servers may not support that RFC. To quote the RFC:
|
…one of '\n' for the FTP protocol
@serhiy-storchaka OpenJDK: http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/81ddd5fc5a4e |
@orsenthil, the discussion here is rather fragmented, so I may have missed something, but I still stand by my view that changing urlsplit is the wrong way: https://bugs.python.org/issue29606#msg292413. |
@@ -1502,6 +1502,9 @@ def ftp_open(self, req): | |||
host = req.host | |||
if not host: | |||
raise URLError('ftp error: no host given') | |||
target_host = unquote(host) | |||
if '\n' in target_host: | |||
raise URLError("illegal ftp host") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to keep the "ftp error" prefix for the error message, so:
ftp error: illegal host
@@ -1502,6 +1502,9 @@ def ftp_open(self, req): | |||
host = req.host | |||
if not host: | |||
raise URLError('ftp error: no host given') | |||
target_host = unquote(host) | |||
if '\n' in target_host: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also blacklist \r?
'FTP://foo:bar%0d%[email protected]/file.png', | ||
'ftp://foo:bar%[email protected]/file.png', | ||
'fTp://foo:bar%[email protected]/file.png', | ||
'FTP://foo:bar%[email protected]/file.png' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that it's interesting to test different cases, I suggest to only test %0d%0a and %0a, so only keep two tests using ftp:// prefix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested this code in master, and it doesn't work: URLopener.open_ftp() is used, and this code is not patched to check for \n (%0a).
with self.assertRaises(urllib.error.URLError) as e: | ||
urlopen(host) | ||
self.assertFalse(e.exception.filename) | ||
self.assertTrue(e.exception.reason) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test is invalid: it must check that the error contains "illegal host". In my case, the test only succeded because of another URLError.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example, the test pass if the connection fails with <urlopen error ftp error ConnectionRefusedError(111, 'Connection refused')>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I mentioned above, the tests should also include injection attempts on directories and filenames. After all, these portions of a URL illicit different FTP commands at different times.
@ecbftw |
I don't have time to develop a patch for this. I'm an extremely busy guy. Most security folks are. But I can lend my insight. |
bpo-29606: urllib throwing an exception on any URLs that contain one of '\r\n' for the FTP protocol.