hacking on msfweb

git-svn-id: file:///home/svn/incoming/trunk@3069 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Matt Miller 2005-11-24 03:31:23 +00:00
parent def6c64abf
commit adc09f4aa1
10 changed files with 481 additions and 47 deletions

BIN
data/msfweb/images/logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

15
data/msfweb/index.rhtml Normal file
View File

@ -0,0 +1,15 @@
<%
if ($:.include?(driver.server_local_directory) == false)
$:.unshift(driver.server_local_directory)
require 'msfweb_common'
end
%>
<%= Msf::Ui::Web::Common.header %>
<br>
<div align='center'>
Welcome to the Metasploit Framework.
</div>
<%= Msf::Ui::Web::Common.footer %>

View File

@ -0,0 +1,60 @@
module Msf
module Ui
module Web
###
#
# This class implements helper methods for sharing across web pages.
#
###
module Common
def self.header(active = "none")
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">
<html>
<head>
<title>Metasploit Framework Web Console v<%= framework.version %></title>
<link type='text/css' rel='stylesheet' href='style.css'/>
</head>
<body>
<br/>
<div align='center'>
<img src='images/logo.jpg' alt='msfweb'/>
</div>
<table align='center' cellpadding='8' border='0' cellspacing='1' width='100%' class='tblInner'>
<tr>
<td>
<table align='center' cellpadding='8' cellspacing='1' width='100%' class='tblOuter'>
<tr>
<td class='tab" + ((active == "exploits") ? "Light" : "Dark") + "' width='33%' align='center'>
<a href='exploits.rhtml'>EXPLOITS</a>
</td>
<td class='tab" + ((active == "payloads") ? "Light" : "Dark") + "' width='33%' align='center'>
<a href='payloads.rhtml'>PAYLOADS</a>
</td>
<td class='tab" + ((active == "sessions") ? "Light" : "Dark") + "' width='33%' align='center'>
<a href='sessions.rhtml'>SESSIONS</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
"
end
def self.footer
"
<br/>
</body>
</html>
"
end
end
end
end
end

243
data/msfweb/style.css Normal file
View File

@ -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;
}

View File

@ -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.
#

View File

@ -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.

View File

@ -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.
#

View File

@ -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

View File

@ -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 =
"<html><head>" +
"<title>404 Not Found</title" +
"</head><body>" +
"<h1>Not found</h1>" +
"The requested URL #{request.resource} was not found on this server.<p><hr>" +
"</body></html>"
# 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 =
"<html><head>" +
"<title>404 Not Found</title" +
"</head><body>" +
"<h1>Not found</h1>" +
"The requested URL #{request.resource} was not found on this server.<p><hr>" +
"</body></html>"
# Send the response to the client like what
cli.send_response(resp)
end
end

7
msfweb
View File

@ -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