Skip to content

Unsafe directory traversal#3

Open
jhlywa wants to merge 7 commits into
elli-lib:developfrom
jhlywa:develop
Open

Unsafe directory traversal#3
jhlywa wants to merge 7 commits into
elli-lib:developfrom
jhlywa:develop

Conversation

@jhlywa

@jhlywa jhlywa commented Oct 4, 2018

Copy link
Copy Markdown

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

coveralls commented Oct 4, 2018

Copy link
Copy Markdown

Coverage Status

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

@jhlywa

jhlywa commented Oct 4, 2018

Copy link
Copy Markdown
Author

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

@yurrriq

yurrriq commented Oct 4, 2018

Copy link
Copy Markdown
Member

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
Comment thread src/elli_static.erl Outdated
%% 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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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.

{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
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good call.

@yurrriq

yurrriq commented Oct 8, 2018

Copy link
Copy Markdown
Member

Thoughts, @elli-lib/team?

@deadtrickster

Copy link
Copy Markdown
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

jhlywa commented Oct 15, 2018

Copy link
Copy Markdown
Author

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

yurrriq commented Oct 15, 2018

Copy link
Copy Markdown
Member

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

@yurrriq

yurrriq commented Oct 23, 2018

Copy link
Copy Markdown
Member

LGTM. What do you think, @deadtrickster?

@jhlywa

jhlywa commented Oct 24, 2018

Copy link
Copy Markdown
Author

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

@yurrriq

yurrriq commented Oct 24, 2018

Copy link
Copy Markdown
Member

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