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

Unsafe directory traversal #3

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open

Conversation

jhlywa
Copy link

@jhlywa jhlywa commented Oct 4, 2018

The maybe_file/3 function doesn't sanitize input which allows unsafe directory traversal. I've added a failing unsafe_traversal test which demonstrates this by reading /etc/passwd. I'll follow up shortly with a fix.

BTW - I think elli is awesome!

jhlywa added 2 commits October 3, 2018 22:32
Paths are now verified with filename:safe_relative_path/1 to ensure they
don't refer to files outside of the user-supplied static directory.
@jhlywa jhlywa changed the title Add test demonstrating unsafe directory traversal Unsafe directory traversal Oct 4, 2018
@coveralls
Copy link

coveralls commented Oct 4, 2018

Coverage Status

Coverage increased (+2.1%) to 86.486% when pulling ed51c07 on jhlywa:develop into af44305 on elli-lib:develop.

@jhlywa
Copy link
Author

jhlywa commented Oct 4, 2018

I'll backport safe_relative_path to provide 18.x - 19.12 compatibility.

@yurrriq
Copy link
Member

yurrriq commented Oct 4, 2018

Thanks for this! I look forward to the backport of filename:safe_relative_path/1.

Further PRs are most welcome too! As it stands, elli_static is not quite ready for wide adoption.

@jhlywa jhlywa force-pushed the develop branch 3 times, most recently from 9008952 to fa50764 Compare October 8, 2018 19:00
%% OTP_RELEASE macro was introduced in 21, `filename:safe_relative_path/1' in
%% 19.3, so the code below is safe
-ifdef(OTP_RELEASE).
-ifdef(?OTP_RELEASE >= 21).
Copy link
Member

Choose a reason for hiding this comment

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

I don't think I've seen this sort of ifdef before, but it appears to work as desired.

Copy link
Author

Choose a reason for hiding this comment

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

My preference would be to defer to filename:safe_relative_path/1 if available. However, checking this at runtime (via module_info(exports)) caused lots of coverall coverage complaints.

Xref and dialyzer are run under the test profile, so in-module eunit tests ended up failing xref right out of the gate (elli_static:safe_relative_path_test/0 is unused export). Doh!

I didn't want to introduce a new module, but I suppose I could create something like elli_static_utils, place safe_relative_path/1 in there, and test independently of the OTP version. The utils module would be a cleaner approach IMO.

Copy link
Member

Choose a reason for hiding this comment

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

👍 to a utils module, if you're up for it.

@@ -48,6 +54,12 @@ unsafe_traversal() ->
{ok, Response} = httpc:request("http://localhost:3000/elli_static/" ++ Path),
?assertMatch({{"HTTP/1.1",404,"Not Found"}, _Headers, "Not Found"}, Response).

invalid_path_separator() ->
Copy link
Member

Choose a reason for hiding this comment

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

Good call.

@yurrriq
Copy link
Member

yurrriq commented Oct 8, 2018

Thoughts, @elli-lib/team?

@deadtrickster
Copy link
Member

hi, since we are there let's learn from

https://www.owasp.org/index.php/Path_Traversal
https://www.owasp.org/index.php/File_System#Path_traversal
https://www.owasp.org/index.php/Testing_Directory_traversal/file_include_(OTG-AUTHZ-001)

I would suggest reusing their examples as test cases and maybe even throw proper

@jhlywa
Copy link
Author

jhlywa commented Oct 15, 2018

I'm under the assumption that we should we be calling the filename version of safe_relative_path if available (e.g. if they patch/upgrade the OTP version, we'd get the changes for "free"). This sounds like a good idea, until you run xref with older OTP versions which complains about filename:safe_relative_path being an undefined function: https://travis-ci.org/elli-lib/elli_static/jobs/441451130#L473

I'm not sure there's any way to silence xref without either:

  • a). using the OTP_RELEASE macro, or
  • b). always using the backported version of safe_relative_path/1

Thoughts?

@yurrriq
Copy link
Member

yurrriq commented Oct 15, 2018

The common approach, I think, is to use Rebar3's platform_define and ifdef, e.g.

@yurrriq
Copy link
Member

yurrriq commented Oct 23, 2018

LGTM. What do you think, @deadtrickster?

@jhlywa
Copy link
Author

jhlywa commented Oct 24, 2018

I probably need to add additional test cases per @deadtrickster's suggestions.

@yurrriq
Copy link
Member

yurrriq commented Oct 24, 2018

That would be great. I'd also be amenable to pulling that out to a new issue, I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants