Skip to content
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-43223: [SECURITY] Patched Open Redirection In SimpleHTTPServer Module #24848

Closed
wants to merge 1 commit into from

Conversation

hamzaavvan
Copy link

@hamzaavvan hamzaavvan commented Mar 13, 2021

Due to no protection against multiple (/) at the beginning of a url an attacker could achieve an open redirection by crafting a malformed URI followed by an existing directory.

Payload: http://127.0.0.1:8000//attacker.com/..%2f..%2f../anyexistingdirectory

The main reason behind open redirection is that there's no (/) at the end of anyexistingdirectory because the server is checking for the path supplied is a valid directory at send_head() method from Lib/http/server.py. Right after that, it's checking for the path ending with a (/) or not. So, if there's no (/) at the end of the path then the server will issue a Location header to redirect the web client to that specific directory.

While issuing the redirection, this part //attacker.com/..%2f..%2f../anyexistingdirectory will be sent to the Location header's value due to which any web client or browser will consider it as a new url because of multiple (/) at the beginning of the path.

So to mitigate this issue I decided to use regex to replace all the occurrences of (/) from the beginning of the path.

 self.path = re.sub(r'(^(/|\\)+)', '/', self.path)

This regex will replace multiple entries (if present) of (/) or (\) from the beginning of the path. So that the path would be:

  1. //attacker.com/..%2f..%2f../anyexistingdirectory -> /attacker.com/..%2f..%2f../anyexistingdirectory
  2. //\attacker.com/..%2f..%2f../anyexistingdirectory -> /attacker.com/..%2f..%2f../anyexistingdirectory
  3. \//\attacker.com/..%2f..%2f../anyexistingdirectory -> /attacker.com/..%2f..%2f../anyexistingdirectory

And according to these test cases there was no redirection issued from the server after implementing the fix.

https://bugs.python.org/issue43223

@hamzaavvan hamzaavvan changed the title bpo-43223: Patched Open Redirection In SimpleHTTPServer Module bpo-43223: [SECURITY] Patched Open Redirection In SimpleHTTPServer Module Mar 13, 2021
@hamzaavvan hamzaavvan force-pushed the fix-issue-43223 branch 2 times, most recently from e2137b6 to 403490c Compare March 16, 2021 17:42
Lib/http/server.py Outdated Show resolved Hide resolved
@hamzaavvan hamzaavvan force-pushed the fix-issue-43223 branch 3 times, most recently from f61138a to 0fe6eed Compare March 16, 2021 18:09
Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please try to write an unit test?

Lib/http/server.py Outdated Show resolved Hide resolved
Lib/http/server.py Outdated Show resolved Hide resolved
@github-actions
Copy link

This PR is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale Stale PR or inactive for long period of time. label Apr 18, 2021
@hamzaavvan
Copy link
Author

Sorry I was busy with my other projects.
Will be pushing the test case shortly.

@hamzaavvan
Copy link
Author

Since I'm new to writing test cases, please help me in correcting the code if something went wrong.

@github-actions github-actions bot removed the stale Stale PR or inactive for long period of time. label May 7, 2021
Fix an open redirection vulnerability in the HTTP server when a URL contains ``//``.
Added test case for bpo-43223 patch
@hamzaavvan
Copy link
Author

@vstinner please have a look at the unit test.


def test_http_parse_request(self):
self.assertEqual(re.sub(r'^/+', '/', '//test.com'), '/test.com', '//test.com should be converted to a proper relative path')
self.assertEqual(re.sub(r'^/+', '/', '///test.com'), '/test.com', '///test.com should be converted to a proper relative path')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't test anything useful. It only checks that some regular expression matches two strings. Since your code change is in http.server, your test should execute the http.server path that you changed.

A good test should fail without your code change to http.server, and pass with your change.

Copy link
Author

@hamzaavvan hamzaavvan Aug 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I've been away due to my workload. But now as I've got some spare time I can do it better. As I've already said earlier that I'm new to writing these test cases and after checking out your comment I'm still confused about your requirements

Can you please elaborate these two statements:

Since your code change is in http.server, your test should execute the http.server path that you changed.

and this one:

A good test should fail without your code change to http.server, and pass with your change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hamzaavvan, to put it in the simplest terms:

  • on a clean checkout of the main branch, write a test that fails because it triggers the problem described in BPO-43223; this will prove we have a problem;
  • then include your fix to prove that the fix solved the problem.

The test will have to actually run the HTTP server to be useful.

@bedevere-bot
Copy link

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@jhadvig
Copy link

jhadvig commented Apr 8, 2022

@hamzaavvan ping :)

@hamzaavvan
Copy link
Author

hamzaavvan commented Apr 8, 2022 via email

@gpshead
Copy link
Member

gpshead commented Jun 15, 2022

This PR has been replaced by #93879

@gpshead gpshead closed this Jun 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants