2011-05-23 04:07:54 -04:00
|
|
|
require 'rack/protection'
|
|
|
|
|
|
|
|
module Rack
|
|
|
|
module Protection
|
2011-05-24 07:23:57 -04:00
|
|
|
##
|
|
|
|
# Prevented attack:: Directory traversal
|
|
|
|
# Supported browsers:: all
|
|
|
|
# More infos:: http://en.wikipedia.org/wiki/Directory_traversal
|
|
|
|
#
|
|
|
|
# Unescapes '/' and '.', expands +path_info+.
|
|
|
|
# Thus <tt>GET /foo/%2e%2e%2fbar</tt> becomes <tt>GET /bar</tt>.
|
2011-05-23 04:07:54 -04:00
|
|
|
class PathTraversal < Base
|
2011-05-24 11:59:33 -04:00
|
|
|
def call(env)
|
|
|
|
path_was = env["PATH_INFO"]
|
2012-05-27 17:17:39 -04:00
|
|
|
env["PATH_INFO"] = cleanup path_was if path_was && !path_was.empty?
|
2011-05-24 11:59:33 -04:00
|
|
|
app.call env
|
|
|
|
ensure
|
|
|
|
env["PATH_INFO"] = path_was
|
|
|
|
end
|
|
|
|
|
|
|
|
def cleanup(path)
|
2019-04-12 16:29:34 -04:00
|
|
|
encoding = path.encoding
|
|
|
|
dot = '.'.encode(encoding)
|
|
|
|
slash = '/'.encode(encoding)
|
|
|
|
backslash = '\\'.encode(encoding)
|
2013-04-15 22:12:58 -04:00
|
|
|
|
2011-10-01 19:44:39 -04:00
|
|
|
parts = []
|
2018-01-08 23:48:01 -05:00
|
|
|
unescaped = path.gsub(/%2e/i, dot).gsub(/%2f/i, slash).gsub(/%5c/i, backslash)
|
|
|
|
unescaped = unescaped.gsub(backslash, slash)
|
2011-10-01 19:44:39 -04:00
|
|
|
|
2013-04-15 22:12:58 -04:00
|
|
|
unescaped.split(slash).each do |part|
|
|
|
|
next if part.empty? or part == dot
|
2011-10-01 19:44:39 -04:00
|
|
|
part == '..' ? parts.pop : parts << part
|
|
|
|
end
|
|
|
|
|
2013-04-15 22:12:58 -04:00
|
|
|
cleaned = slash + parts.join(slash)
|
|
|
|
cleaned << slash if parts.any? and unescaped =~ %r{/\.{0,2}$}
|
2011-10-01 19:44:39 -04:00
|
|
|
cleaned
|
2011-05-24 11:59:33 -04:00
|
|
|
end
|
2011-05-23 04:07:54 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|