Adds a monkey-patch for the WEBrick directory traversal flaw

git-svn-id: file:///home/svn/framework3/trunk@5434 4d416f70-5f16-0410-b530-b9f4589650da
unstable
HD Moore 2008-03-06 17:21:45 +00:00
parent 52a64d4d9f
commit 032edb7e39
2 changed files with 78 additions and 0 deletions

View File

@ -33,6 +33,13 @@ end
msfbase = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
$:.unshift(File.join(File.dirname(msfbase), '..', '..', '..', 'lib'))
# Monkey patch the webrick vulnerability
if(Object.const_defined?(:WEBrick))
load(File.join(File.dirname(msfbase), "..", "patches", "filehandler.rb"))
end
require 'rex'
require 'msf/ui'
require 'msf/base'

View File

@ -0,0 +1,71 @@
#
# Monkey patch the webrick vulnerability
#
$stderr.puts "[*] WEBrick directory traversal patch loaded"
module WEBrick
module HTTPServlet
class FileHandler < AbstractServlet
def service(req, res)
# if this class is mounted on "/" and /~username is requested.
# we're going to override path informations before invoking service.
if defined?(Etc) && @options[:UserDir] && req.script_name.empty?
if %r|^(/~([^/]+))| =~ req.path_info
script_name, user = $1, $2
path_info = $'
begin
passwd = Etc::getpwnam(user)
@root = File::join(passwd.dir, @options[:UserDir])
req.script_name = script_name
req.path_info = path_info
rescue
@logger.debug "#{self.class}#do_GET: getpwnam(#{user}) failed"
end
end
end
prevent_directory_traversal(req, res)
super(req, res)
end
private
def prevent_directory_traversal(req, res)
# Preventing directory traversal on DOSISH platforms;
# Backslashes (0x5c) in path_info are not interpreted as special
# character in URI notation. So the value of path_info should be
# normalize before accessing to the filesystem.
if File::ALT_SEPARATOR
# File.expand_path removes the trailing path separator.
# Adding a character is a workaround to save it.
# File.expand_path("/aaa/") #=> "/aaa"
# File.expand_path("/aaa/" + "x") #=> "/aaa/x"
expanded = File.expand_path(req.path_info + "x")
expanded[-1, 1] = "" # remove trailing "x"
req.path_info = expanded
end
end
def check_filename(req, res, name)
@options[:NondisclosureName].each{|pattern|
if File.fnmatch("/#{pattern}", name, File::FNM_CASEFOLD)
@logger.warn("the request refers nondisclosure name `#{name}'.")
raise HTTPStatus::NotFound, "`#{req.path}' not found."
end
}
end
def nondisclosure_name?(name)
@options[:NondisclosureName].each{|pattern|
if File.fnmatch(pattern, name, File::FNM_CASEFOLD)
return true
end
}
return false
end
end
end
end