+ "
+ end
+
+ def self.footer
+ "
+
+
+
+ "
+ end
+
+end
+
+end
+end
+end
diff --git a/data/msfweb/style.css b/data/msfweb/style.css
new file mode 100644
index 0000000000..7ecbbb2c2b
--- /dev/null
+++ b/data/msfweb/style.css
@@ -0,0 +1,243 @@
+html {
+ margin: 0px;
+ padding: 0px;
+}
+
+body
+{
+ background: white;
+ font-family: Verdana, Tahoma, Arial, Helvetica, sans-serif;
+ color: black;
+ font-size: 10pt;
+ margin: 0.1cm 0.5cm 0.1cm 0.5cm;
+}
+
+A {
+ font-size: 10pt;
+ text-decoration: none;
+ color: navy;
+ font-weight: bold;
+}
+
+
+A:hover {
+ text-decoration: underline;
+}
+
+.tabDark {
+ background: #dddddd;
+}
+A.tabDark {
+
+}
+
+.tabLight {
+ background: #eeeeee;
+}
+A.tabLight {
+
+}
+
+.tabActive {
+
+}
+A.tabActive {
+ text-decoration: underline;
+}
+
+
+.sectionTitle {
+ color: black;
+ font-size: 10pt;
+ font-weight: bold;
+}
+
+.listBody {
+ background: white;
+ color: black;
+ font-size: 10pt;
+}
+
+A.nav {
+ font-size: 10pt;
+ font-weight: bold;
+}
+
+.nav {
+ font-size: 10pt;
+ font-weight: normal;
+ font-weight: bold;
+}
+
+.navHead {
+ font-size: 10pt;
+ font-weight: bold;
+}
+
+.copy {
+ font-size: 10pt;
+ font-variant: small-caps;
+}
+
+.modHead {
+ font-size: 10pt;
+ font-weight: bold;
+ color: white;
+}
+
+.shellcode {
+ font-size: 10pt;
+ font-weight: normal;
+ color: black;
+}
+
+.boldText {
+ font-size: 10pt;
+ color: black;
+ font-weight: bold;
+}
+
+.moduleOutput {
+ font-size: 10pt;
+ color: black;
+}
+
+.moduleInfo {
+ font-size: 10pt;
+ color: black;
+}
+
+.textNormal {
+ font-size: 10pt;
+ color: black;
+}
+
+.textBold {
+ font-size: 10pt;
+ color: black;
+ font-weight: bold;
+}
+
+.textBoldDark {
+ font-size: 10pt;
+ color: grey;
+ font-weight: bold;
+}
+
+.textBoldBright {
+ font-size: 10pt;
+ color: black;
+ font-weight: bold;
+}
+
+
+.textNormalColorA {
+ background: #eeeeee;
+ font-size: 10pt;
+ font-weight: normal;
+}
+
+.textBoldColorA {
+ background: #eeeeee;
+ font-size: 10pt;
+ font-weight: bold;
+}
+
+
+.textNormalColorB {
+ background: #dddddd;
+ font-size: 10pt;
+ font-weight: normal;
+}
+
+.textBoldColorB {
+ background: #dddddd;
+ font-size: 10pt;
+ font-weight: bold;
+}
+
+.tblOuter {
+ background: black;
+}
+
+.tblInner {
+ background: white;
+}
+
+
+select {
+ color: black;
+ background: #eeeeee;
+ font-weight: bold;
+ padding: 2px 2px 2px 2px;
+}
+
+input {
+ font-weight: bold;
+ color: black;
+ background: #eeeeee;
+ color: black;
+ padding: 2px 10px 2px 10px;
+ border: 1px solid grey;
+}
+
+input.button {
+ border-left: 1px solid grey;
+ border-top: 1px solid grey;
+ border-bottom: 2px solid black;
+ border-right: 2px solid black;
+ padding: 1px 5px 1px 5px;
+}
+
+.iconset
+{
+ background: white;
+ padding: 2px 2px 2px 2px;
+ border: 1px solid white;
+}
+
+.moduleList
+{
+ white-space: nowrap;
+}
+
+.moduleIcons
+{
+ border-top: 1px solid #aaaaaa;
+ border-left: 1em solid #aaaaaa;
+ padding: 0.5em 0em 0em 0.25em;
+}
+
+.moduleName
+{
+ border-top: 1px solid #aaaaaa;
+ padding: 0.5em 0.5em 0em 0em;
+}
+
+.moduleSpacer
+{
+ padding: 10px 0px 0px 0px;
+ margin: 0;
+}
+
+.CommandBar {
+
+}
+
+#CommandBarList {
+ padding: 0 1px 1px;
+ margin-left: 0;
+}
+
+#CommandBarList li {
+ list-style: none;
+ margin: 0;
+ display: inline;
+}
+
+#CommandBarList li a {
+}
+
+#CommandBarList li a:hover {
+ border-bottom: 1px solid #black;
+}
diff --git a/lib/msf/base/config.rb b/lib/msf/base/config.rb
index f6a45ccdbb..5d49393bb3 100644
--- a/lib/msf/base/config.rb
+++ b/lib/msf/base/config.rb
@@ -37,7 +37,8 @@ class Config < Hash
'ModuleDirectory' => "modules",
'LogDirectory' => "logs",
'SessionLogDirectory' => "logs/sessions",
- 'PluginDirectory' => "plugins"
+ 'PluginDirectory' => "plugins",
+ 'DataDirectory' => "data"
}
##
@@ -94,6 +95,13 @@ class Config < Hash
def self.user_module_directory
self.new.user_module_directory
end
+
+ #
+ # Calls the instance method.
+ #
+ def self.data_directory
+ self.new.data_directory
+ end
#
# Calls the instance method.
@@ -186,6 +194,13 @@ class Config < Hash
config_directory + FileSep + "modules"
end
+ #
+ # Returns the data directory
+ #
+ def data_directory
+ install_root + FileSep + self['DataDirectory']
+ end
+
#
# Initializes configuration, creating directories as necessary.
#
diff --git a/lib/msf/core/framework.rb b/lib/msf/core/framework.rb
index 096610394b..edbe371840 100644
--- a/lib/msf/core/framework.rb
+++ b/lib/msf/core/framework.rb
@@ -83,6 +83,13 @@ class Framework
return modules.recon
end
+ #
+ # Returns the framework version in Major.Minor format.
+ #
+ def version
+ Version
+ end
+
#
# Event management interface for registering event handler subscribers and
# for interacting with the correlation engine.
diff --git a/lib/msf/ui/web/driver.rb b/lib/msf/ui/web/driver.rb
index 69561484cc..1d99e0c80f 100644
--- a/lib/msf/ui/web/driver.rb
+++ b/lib/msf/ui/web/driver.rb
@@ -1,3 +1,4 @@
+require 'rex/proto/http'
require 'msf/core'
require 'msf/base'
require 'msf/ui'
@@ -20,6 +21,27 @@ class Driver < Msf::Ui::Driver
ConfigCore = "framework/core"
ConfigGroup = "framework/ui/web"
+ #
+ # The msfweb resource handler that wrappers the default Erb handler.
+ #
+ class ResourceHandler < Rex::Proto::Http::Handler::Erb
+ def initialize(server, root_path, framework, driver, opts = {})
+ opts['ErbCallback'] = ::Proc.new { |erb, cli, request, response|
+ query_string = request.qstring
+ meta_vars = request.meta_vars
+ erb.result(binding)
+ }
+
+ super(server, root_path, opts)
+
+ self.framework = framework
+ self.driver = driver
+ end
+
+ attr_accessor :framework # :nodoc:
+ attr_accessor :driver # :nodoc:
+ end
+
#
# The default port to listen for HTTP requests on.
#
@@ -33,7 +55,17 @@ class Driver < Msf::Ui::Driver
#
# The default root directory for requests.
#
- DefaultRoot = "/msfweb"
+ DefaultRoot = "/"
+
+ #
+ # The default local directory for msfweb.
+ #
+ DefaultLocalDirectory = Msf::Config.data_directory + File::SEPARATOR + "msfweb"
+
+ #
+ # The default index script.
+ #
+ DefaultIndex = "index.rhtml"
#
# Initializes a web driver instance and prepares it for listening to HTTP
@@ -67,12 +99,16 @@ class Driver < Msf::Ui::Driver
ilog("Web server started on #{host}:#{port}", LogSource)
- service.add_resource(
+ # Mount the server root directory on the web server instance. We pass
+ # it a custom ErbCallback so that we can have it run in a context that
+ # has the framework instance defined.
+ service.mount(
server_root,
- 'Directory' => true,
- 'Proc' => Proc.new { |cli, req|
- on_request(cli, req)
- })
+ ResourceHandler,
+ false,
+ server_local_directory,
+ framework,
+ self)
# Wait for the termination event to be set.
term_event.wait
@@ -93,12 +129,26 @@ class Driver < Msf::Ui::Driver
end
#
- # Returns the root resource name, such as '/msfweb'
+ # Returns the root resource name, such as '/msfweb'.
#
def server_root
opts['ServerRoot'] || DefaultRoot
end
+ #
+ # Returns the server index, such as 'index.rhtml'.
+ #
+ def server_index
+ opts['ServerIndex'] || DefaultIndex
+ end
+
+ #
+ # Returns the local directory that will hold the files to be serviced.
+ #
+ def server_local_directory
+ opts['ServerLocalDirectory'] || DefaultLocalDirectory
+ end
+
#
# The framework instance associated with this driver.
#
diff --git a/lib/rex/proto/http/handler/erb.rb b/lib/rex/proto/http/handler/erb.rb
index 3200f06b21..7e97372135 100644
--- a/lib/rex/proto/http/handler/erb.rb
+++ b/lib/rex/proto/http/handler/erb.rb
@@ -43,6 +43,9 @@ class Handler::Erb < Handler
wlog("Erb::on_request: Dangerous request performed: #{resource}",
LogSource)
return
+ # If the request is for the root directory, use the document index file.
+ elsif (resource == '/')
+ resource += opts['DocumentIndex'] || 'index.rhtml'
end
begin
@@ -51,22 +54,28 @@ class Handler::Erb < Handler
# Calculate the actual file path on disk.
file_path = root_path + resource
- puts "file path is #{file_path}"
-
# Serialize the contents of the file
data = ::IO.readlines(file_path).join
- # Evaluate the data and set the output as the response body.
- resp.body = evaluate(ERB.new(data), cli, req, resp)
+ # Set the content-type to text/html by default. We do this before
+ # evaluation so that the script can change it.
+ resp['Content-Type'] = server.mime_type(resource)
- # Set the content-type to text/html by default.
- resp['Content-Type'] = opts['MimeType']
+ # If the requested file is a ruby html file, evaluate it.
+ if (File.extname(file_path) == ".rhtml")
+ # Evaluate the data and set the output as the response body.
+ resp.body = evaluate(ERB.new(data), cli, req, resp)
+ # Otherwise, just set the body to the data that was read.
+ else
+ resp.body = data
+ end
rescue
- elog("Erb::on_request: #{$!}\n\n#{$@.join("\n")}", LogSource)
+ elog("Erb::on_request: #{$!}", LogSource)
- puts "exception: #{$!} #{$@.join("\n")}"
+ # Send a standard 404 message.
+ server.send_e404(cli, req)
- resp = Response::E404.new
+ resp = nil
end
# Send the response to the
@@ -83,8 +92,8 @@ class Handler::Erb < Handler
def evaluate(erb, cli, request, response)
# If the thing that created this handler wanted us to use a callback
# instead of the default behavior, then let's do that.
- if (opts['Callback'])
- opts['Callback'].call(erb, cli, request, response)
+ if (opts['ErbCallback'])
+ opts['ErbCallback'].call(erb, cli, request, response)
else
Module.new.module_eval {
query_string = request.qstring
diff --git a/lib/rex/proto/http/server.rb b/lib/rex/proto/http/server.rb
index 91760fa5ec..a05faf82d8 100644
--- a/lib/rex/proto/http/server.rb
+++ b/lib/rex/proto/http/server.rb
@@ -69,8 +69,35 @@ class Server
include Proto
+ #
+ # A hash that associated a file extension with a mime type for use as the
+ # content type of responses.
+ #
+ ExtensionMimeTypes =
+ {
+ "rhtml" => "text/html",
+ "html" => "text/html",
+ "htm" => "text/htm",
+ "jpg" => "image/jpeg",
+ "jpeg" => "image/jpeg",
+ "jpeg" => "image/jpeg",
+ "gif" => "image/gif",
+ "png" => "image/png",
+ "bmp" => "image/bmp",
+ "txt" => "text/plain",
+ "css" => "text/css",
+ }
+
+ #
+ # The default server name that will be returned in the Server attribute of
+ # a response.
+ #
DefaultServer = "Rex"
+ #
+ # Initializes an HTTP server as listening on the provided port and
+ # hostname.
+ #
def initialize(port = 80, listen_host = '0.0.0.0')
self.listen_host = listen_host
self.listen_port = port
@@ -170,6 +197,38 @@ class Server
resp['Server'] = DefaultServer
end
+ #
+ # Returns the mime type associated with the supplied file. Right now the
+ # set of mime types is fairly limited.
+ #
+ def mime_type(file)
+ type = nil
+
+ if (file =~ /\.(.+?)$/)
+ type = ExtensionMimeTypes[$1.downcase]
+ end
+
+ type || "text/plain"
+ end
+
+ #
+ # Sends a 404 error to the client for a given request.
+ #
+ def send_e404(cli, request)
+ resp = Response::E404.new
+
+ resp.body =
+ "" +
+ "404 Not Found" +
+ "
Not found
" +
+ "The requested URL #{request.resource} was not found on this server." +
+ ""
+
+ # Send the response to the client like what
+ cli.send_response(resp)
+ end
+
attr_accessor :listen_port, :listen_host
protected
@@ -233,7 +292,6 @@ protected
end
}
-begin
if (p)
# Create an instance of the handler for this resource
handler = p[0].new(self, *p[2])
@@ -242,9 +300,10 @@ begin
if (p[0].relative_resource_required?)
# Substituted the mount point root in the request to make things
# relative to the mount point.
- request.relative_resource = request.resource.gsub(root, '')
+ request.relative_resource = request.resource.gsub(/^#{root}/, '')
request.relative_resource = '/' + request.relative_resource if (request.relative_resource !~ /^\//)
end
+
# If we found the resource handler for this resource, call its
# procedure.
@@ -266,27 +325,6 @@ begin
if (cli.keepalive == false)
close_client(cli)
end
-rescue
- puts "bleh #{$!} #{$@.join("\n")}"
-end
- end
-
- #
- # Sends a 404 error to the client for a given request.
- #
- def send_e404(cli, request)
- resp = Response::E404.new
-
- resp.body =
- "" +
- "404 Not Found" +
- "
Not found
" +
- "The requested URL #{request.resource} was not found on this server." +
- ""
-
- # Send the response to the client like what
- cli.send_response(resp)
end
end
diff --git a/msfweb b/msfweb
index 5c5f16ae03..8469ec891d 100755
--- a/msfweb
+++ b/msfweb
@@ -31,8 +31,5 @@ arguments.parse(ARGV) { |opt, idx, val|
end
}
-# Create the driver instance.
-driver = Msf::Ui::Web::Driver.new(opts)
-
-# Run with it.
-driver.run
+# Create the driver instance and run it.
+Msf::Ui::Web::Driver.new(opts).run