Basic session support for the web console
git-svn-id: file:///home/svn/framework3/trunk@4344 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
f4fd1051da
commit
d0f3f574b0
|
@ -10,9 +10,9 @@ class ConsoleController < ApplicationController
|
|||
def index
|
||||
|
||||
# Work around rails stupidity
|
||||
if(not $webrick_hooked)
|
||||
if(not $webrick_hooked_console)
|
||||
|
||||
$webrick.mount_proc("/_session") do |req, res|
|
||||
$webrick.mount_proc("/_console") do |req, res|
|
||||
|
||||
res['Content-Type'] = "text/javascript"
|
||||
|
||||
|
@ -22,11 +22,12 @@ class ConsoleController < ApplicationController
|
|||
|
||||
out = ''
|
||||
tsp = Time.now.to_i
|
||||
prompt_old = console.prompt
|
||||
|
||||
# Poll the console output for 15 seconds
|
||||
while( tsp + 15 > Time.now.to_i and out.length == 0)
|
||||
while( tsp + 15 > Time.now.to_i and out.length == 0 and console.prompt == prompt_old)
|
||||
out = console.read()
|
||||
select(nil, nil, nil, 0.25)
|
||||
select(nil, nil, nil, 0.10)
|
||||
end
|
||||
|
||||
out = out.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
|
@ -42,7 +43,7 @@ class ConsoleController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
$webrick_hooked = true
|
||||
$webrick_hooked_console = true
|
||||
end
|
||||
|
||||
cid = params[:id]
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
#
|
||||
# Author: Metasploit LLC
|
||||
# Description: The AJAX console controller of msfweb
|
||||
#
|
||||
|
||||
class SessionsController < ApplicationController
|
||||
layout 'windows'
|
||||
|
||||
|
@ -9,5 +14,57 @@ class SessionsController < ApplicationController
|
|||
end
|
||||
|
||||
def interact
|
||||
# Work around rails stupidity
|
||||
if(not $webrick_hooked_session)
|
||||
|
||||
$webrick.mount_proc("/_session") do |req, res|
|
||||
|
||||
res['Content-Type'] = "text/javascript"
|
||||
|
||||
m = req.path_info.match(/cid=(\d+)/)
|
||||
if (m and m[1] and $msfweb.sessions[m[1].to_i])
|
||||
cid = m[1].to_i
|
||||
|
||||
$msfweb.connect_session(cid)
|
||||
|
||||
out = ''
|
||||
tsp = Time.now.to_i
|
||||
|
||||
# Poll the session output for 15 seconds
|
||||
while( tsp + 15 > Time.now.to_i and out.length == 0)
|
||||
out = $msfweb.read_session(cid)
|
||||
select(nil, nil, nil, 0.10)
|
||||
end
|
||||
|
||||
out = out.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
|
||||
script = "// Metasploit Web Session Data\n"
|
||||
script += "var ses_update = unescape('#{out}');\n"
|
||||
|
||||
res.body = script
|
||||
else
|
||||
res.body = '// Invalid session ID'
|
||||
end
|
||||
end
|
||||
|
||||
$webrick_hooked_session = true
|
||||
end
|
||||
|
||||
cid = params[:id].to_i
|
||||
$msfweb.connect_session(cid)
|
||||
|
||||
if(params[:cmd])
|
||||
|
||||
if (params[:cmd].strip.length > 0)
|
||||
$msfweb.write_session(cid, params[:cmd] + "\n")
|
||||
end
|
||||
|
||||
script = "// Metasploit Web Session Data\n"
|
||||
script += "var ses_update = unescape('');\n"
|
||||
|
||||
send_data(script, :type => "text/javascript")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,2 +1,50 @@
|
|||
<h1>Sessions#interact</h1>
|
||||
<p>Find me in app/views/sessions/interact.rhtml</p>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="eng">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
|
||||
<meta name="Author" content="LMH (lmh@info-pull.com), Metasploit LLC" />
|
||||
<meta name="Copyright" content="(c) 2006, LMH (lmh@info-pull.com), (c) 2006-2007 Metasploit LLC" />
|
||||
<title>msfweb v.3 - console demo</title>
|
||||
<% ["prototype","effects","controls", "window", "application", "session"].each do |js| %>
|
||||
<%= javascript_include_tag js %><% end %>
|
||||
<%= stylesheet_link_tag "msfsession" %>
|
||||
</head>
|
||||
|
||||
<body onload="session_init(<%=params[:id]%>)">
|
||||
|
||||
<div id="session_window">
|
||||
|
||||
<div id="session_output">
|
||||
|
||||
</div>
|
||||
|
||||
<table id="session_command_bar" border=0 padding=4 cellspacing=0 width='100%'>
|
||||
<tr>
|
||||
<td
|
||||
nowrap='true'
|
||||
valign='top'
|
||||
id="session_prompt"
|
||||
>
|
||||
>>
|
||||
</td>
|
||||
<td nowrap='true' width='100%'>
|
||||
|
||||
<textarea
|
||||
id="session_input"
|
||||
class="input"
|
||||
wrap="off"
|
||||
onkeydown="return session_keydown(event)"
|
||||
onkeypress="return session_keypress(event)"
|
||||
rows="1"
|
||||
></textarea>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
|
@ -1,13 +1,24 @@
|
|||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
|
||||
<% if(@sessions.length > 0) %>
|
||||
<table cellpadding="0" cellspacing="0" border="0" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Description</th>
|
||||
<th width="10">ID</th>
|
||||
<th width="40">Target</th>
|
||||
<th width="60">Payload</th>
|
||||
<th width="60">Exploit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @sessions.each_pair do |n,m| %>
|
||||
<tr><td><%= n %></td><td><%= m %></td></tr>
|
||||
<tr>
|
||||
<td><%= n %></td>
|
||||
<td><a href="/sessions/interact/<%= n %>"><%= m.tunnel_peer %></a></td>
|
||||
<td><%= m.via_payload %></td>
|
||||
<td><%= m.via_exploit %></td>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% else %>
|
||||
There are no active sessions, go exploit something ;-)
|
||||
<% end %>
|
||||
|
|
|
@ -55,7 +55,8 @@ require 'msf/base'
|
|||
$msfweb = Msf::Ui::Web::Driver.new({'LogLevel' => 5})
|
||||
$msframework = $msfweb.framework
|
||||
$webrick = nil
|
||||
$webrick_hooked = false
|
||||
$webrick_hooked_console = false
|
||||
$webrick_hooked_session = false
|
||||
|
||||
module WEBrickHooker
|
||||
def initialize(*args)
|
||||
|
|
|
@ -54,7 +54,7 @@ function console_refocus() {
|
|||
}
|
||||
|
||||
function console_read() {
|
||||
new Ajax.Updater("console_update", '/_session/cid=' + console_id, {
|
||||
new Ajax.Updater("console_update", '/_console/cid=' + console_id, {
|
||||
asynchronous:true,
|
||||
evalScripts:true,
|
||||
onComplete:console_read_output
|
||||
|
@ -85,7 +85,7 @@ function console_read_output(req) {
|
|||
console_update_output(req);
|
||||
|
||||
// Reschedule the console reader
|
||||
setTimeout(console_read, 1000);
|
||||
setTimeout(console_read, 1);
|
||||
}
|
||||
|
||||
function console_update_output(req) {
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Copyright (c) 2006 LMH <lmh[at]info-pull.com>
|
||||
* Added to Metasploit under the terms of the Metasploit Framework License v1.2
|
||||
* Additions Copyright (C) 2006-2007 Metasploit LLC
|
||||
*/
|
||||
|
||||
|
||||
var session_id;
|
||||
var session_history = new Array(); // Commands history
|
||||
var session_hindex = 0; // Index to current command history
|
||||
var session_input; // Object to console input
|
||||
var session_output; // Object to console output
|
||||
var session_prompt; // Object to console prompt
|
||||
var session_status;
|
||||
var session_cmdbar;
|
||||
|
||||
// Placeholders
|
||||
var ses_prompt = "";
|
||||
var ses_update = "";
|
||||
var ses_tabbed = "";
|
||||
|
||||
|
||||
|
||||
// Internal commands
|
||||
var cmd_internal =
|
||||
{
|
||||
clear:function() {
|
||||
session_output.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
function status_busy() {
|
||||
session_input.style.color = "red";
|
||||
}
|
||||
|
||||
function status_free() {
|
||||
session_input.style.color = "white";
|
||||
}
|
||||
|
||||
// This function is based on the excellent example:
|
||||
// http://tryruby.hobix.com/js/mouseApp.js
|
||||
function keystroke_block(e) {
|
||||
e.cancelBubble=true;
|
||||
e.returnValue = false;
|
||||
if (window.event && !window.opera) e.keyCode=0;
|
||||
if (e.stopPropagation) e.stopPropagation();
|
||||
if (e.preventDefault) e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
function session_refocus() {
|
||||
session_input.blur();
|
||||
session_input.focus();
|
||||
}
|
||||
|
||||
function session_read() {
|
||||
new Ajax.Updater("session_update", '/_session/cid=' + session_id, {
|
||||
asynchronous:true,
|
||||
evalScripts:true,
|
||||
onComplete:session_read_output
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function session_printline(s, type) {
|
||||
if ((s=String(s))) {
|
||||
var n = document.createElement("div");
|
||||
|
||||
// IE has to use innerText
|
||||
if (n.innerText != undefined) {
|
||||
n.innerText = s;
|
||||
// Firefox uses createTextNode
|
||||
} else {
|
||||
n.appendChild(document.createTextNode(s));
|
||||
}
|
||||
|
||||
n.className = type;
|
||||
session_output.appendChild(n);
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
function session_read_output(req) {
|
||||
// Call the console updated
|
||||
session_update_output(req);
|
||||
|
||||
// Reschedule the console reader
|
||||
setTimeout(session_read, 1);
|
||||
}
|
||||
|
||||
function session_update_output(req) {
|
||||
|
||||
try { eval(req.responseText); } catch(e){ alert(req.responseText); }
|
||||
|
||||
status_free();
|
||||
|
||||
if (ses_update.length > 0) {
|
||||
session_printline(ses_update, 'output_line');
|
||||
}
|
||||
|
||||
session_refocus();
|
||||
}
|
||||
|
||||
|
||||
function session_keypress(e) {
|
||||
if (e.keyCode == 13) { // enter
|
||||
|
||||
session_input.value = (session_input.value.replace(/^ +/,'')).replace(/ +$/,'');
|
||||
|
||||
// ignore duplicate commands in the history
|
||||
if(session_history[session_history.length-1] != session_input.value) {
|
||||
session_history.push(session_input.value);
|
||||
session_hindex = session_history.length - 1;
|
||||
}
|
||||
|
||||
session_printline("\n" + session_input.value, 'output_line')
|
||||
|
||||
if(cmd_internal[session_input.value]) {
|
||||
cmd_internal[session_input.value]();
|
||||
session_input.value = "";
|
||||
session_input.focus();
|
||||
return keystroke_block(e);
|
||||
}
|
||||
|
||||
status_busy();
|
||||
|
||||
new Ajax.Updater("session_update", document.location, {
|
||||
asynchronous:true,
|
||||
evalScripts:true,
|
||||
parameters:"cmd=" + escape(session_input.value),
|
||||
onComplete:session_update_output
|
||||
});
|
||||
|
||||
session_input.value = "";
|
||||
session_input.focus();
|
||||
return keystroke_block(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function session_keydown(e) {
|
||||
|
||||
if (e.keyCode == 38) { // up
|
||||
// TODO: place upper cmd in history on session_input.value
|
||||
|
||||
session_input.value = session_history[session_hindex];
|
||||
if (session_hindex > 0) {
|
||||
session_hindex--;
|
||||
}
|
||||
|
||||
return keystroke_block(e);
|
||||
|
||||
} else if (e.keyCode == 40) { // down
|
||||
|
||||
if (session_hindex < session_history.length - 1) {
|
||||
session_hindex++;
|
||||
}
|
||||
session_input.value = session_history[session_hindex];
|
||||
|
||||
return keystroke_block(e);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function session_init(cid) {
|
||||
|
||||
session_id = cid;
|
||||
session_input = document.getElementById("session_input");
|
||||
session_output = document.getElementById("session_output");
|
||||
session_prompt = document.getElementById("session_prompt");
|
||||
session_status = document.getElementById("session_status");
|
||||
session_cmdbar = document.getElementById("session_command_bar");
|
||||
|
||||
session_refocus();
|
||||
status_free();
|
||||
|
||||
session_read();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -10,8 +10,8 @@ html,body {
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
background: #000000;
|
||||
color: #fff;
|
||||
font-family: monospace;
|
||||
color: #eeeeee;
|
||||
font-family: fixed;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ html,body {
|
|||
|
||||
.input {
|
||||
font: inherit;
|
||||
font-family: monospace;
|
||||
font-family: fixed;
|
||||
background: #000000;
|
||||
border: 0;
|
||||
color: white;
|
||||
|
@ -61,7 +61,7 @@ html,body {
|
|||
color: white;
|
||||
font: inherit;
|
||||
text-align: right;
|
||||
font-family: monospace;
|
||||
font-family: fixed;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2006, LMH <lmh@info-pull.com>
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Standards compliant:
|
||||
* Valid, warning-free CSS: http://jigsaw.w3.org/css-validator
|
||||
*/
|
||||
|
||||
html,body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #000000;
|
||||
color: #eeeeee;
|
||||
font-family: fixed;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#session_window {
|
||||
background: #000000;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
#session_output {
|
||||
width: 100%;
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
background: #000000;
|
||||
}
|
||||
|
||||
.output_line {
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
}
|
||||
|
||||
|
||||
#input {
|
||||
width: 100%;
|
||||
border: none;
|
||||
padding: 0;
|
||||
background: #000000;
|
||||
}
|
||||
|
||||
.input {
|
||||
font: inherit;
|
||||
font-family: fixed;
|
||||
background: #000000;
|
||||
border: 0;
|
||||
color: white;
|
||||
width: 600px;
|
||||
overflow: hidden;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.prompt {
|
||||
color: white;
|
||||
font: inherit;
|
||||
text-align: right;
|
||||
font-family: fixed;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#session_command_bar {
|
||||
background: #000000;
|
||||
}
|
||||
|
||||
#session_status {
|
||||
color: #fff;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
text-transform: smallcaps;
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
module Msf
|
||||
module Ui
|
||||
module Web
|
||||
|
||||
###
|
||||
#
|
||||
# This class implements a console instance for use by the web interface
|
||||
#
|
||||
###
|
||||
|
||||
class WebConsole
|
||||
attr_accessor :pipe
|
||||
attr_accessor :console
|
||||
attr_accessor :console_id
|
||||
attr_accessor :last_access
|
||||
attr_accessor :framework
|
||||
attr_accessor :thread
|
||||
|
||||
class WebConsolePipe < Rex::IO::BidirectionalPipe
|
||||
|
||||
attr_accessor :input
|
||||
attr_accessor :output
|
||||
attr_accessor :prompt
|
||||
attr_accessor :killed
|
||||
|
||||
def intrinsic_shell?
|
||||
true
|
||||
end
|
||||
|
||||
def supports_readline
|
||||
false
|
||||
end
|
||||
|
||||
def _print_prompt
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Wrapper methods around input pipe
|
||||
#
|
||||
|
||||
|
||||
def close
|
||||
self.pipe_input.close
|
||||
end
|
||||
|
||||
def put(*args)
|
||||
self.pipe_input.put(*args)
|
||||
end
|
||||
|
||||
def gets
|
||||
self.pipe_input.gets
|
||||
end
|
||||
|
||||
def pgets
|
||||
self.pipe_input.gets
|
||||
end
|
||||
|
||||
def eof?
|
||||
self.pipe_input.eof?
|
||||
end
|
||||
|
||||
def fd(*args)
|
||||
# Remove the following line to enable full sessions via the console
|
||||
# We really should just hook the on_session() instead...
|
||||
raise ::RuntimeError, "Session interaction should be performed via the Sessions tab"
|
||||
self.pipe_input.fd(*args)
|
||||
end
|
||||
|
||||
def sysread(*args)
|
||||
self.pipe_input.sysread(*args)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Provides some overrides for web-based consoles
|
||||
#
|
||||
module WebConsoleShell
|
||||
|
||||
def supports_color?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(framework, console_id)
|
||||
# Configure the framework
|
||||
self.framework = framework
|
||||
|
||||
# Configure the ID
|
||||
self.console_id = console_id
|
||||
|
||||
# Create a new pipe
|
||||
self.pipe = WebConsolePipe.new
|
||||
self.pipe.input = self.pipe.pipe_input
|
||||
|
||||
# Create a read subscriber
|
||||
self.pipe.create_subscriber('msfweb')
|
||||
|
||||
# Initialize the console with our pipe
|
||||
self.console = Msf::Ui::Console::Driver.new(
|
||||
'msf',
|
||||
'>',
|
||||
{
|
||||
'Framework' => self.framework,
|
||||
'LocalInput' => self.pipe,
|
||||
'LocalOutput' => self.pipe,
|
||||
'AllowCommandPassthru' => false,
|
||||
}
|
||||
)
|
||||
|
||||
self.console.extend(WebConsoleShell)
|
||||
|
||||
self.thread = Thread.new { self.console.run }
|
||||
|
||||
update_access()
|
||||
end
|
||||
|
||||
def update_access
|
||||
self.last_access = Time.now
|
||||
end
|
||||
|
||||
def read
|
||||
update_access
|
||||
|
||||
self.pipe.read_subscriber('msfweb')
|
||||
end
|
||||
|
||||
def write(buf)
|
||||
update_access
|
||||
self.pipe.write_input(buf)
|
||||
end
|
||||
|
||||
def execute(cmd)
|
||||
self.console.run_single(cmd)
|
||||
end
|
||||
|
||||
def prompt
|
||||
self.pipe.prompt
|
||||
end
|
||||
|
||||
def tab_complete(cmd)
|
||||
self.console.tab_complete(cmd)
|
||||
end
|
||||
|
||||
def shutdown
|
||||
self.pipe.killed = true
|
||||
self.pipe.close
|
||||
self.thread.kill
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -8,151 +8,8 @@ module Ui
|
|||
module Web
|
||||
|
||||
require 'rex/io/bidirectional_pipe'
|
||||
require 'msf/ui/web/console'
|
||||
|
||||
###
|
||||
#
|
||||
# This class implements a console instance for use by the web interface
|
||||
#
|
||||
###
|
||||
|
||||
class WebConsole
|
||||
attr_accessor :pipe
|
||||
attr_accessor :console
|
||||
attr_accessor :console_id
|
||||
attr_accessor :last_access
|
||||
attr_accessor :framework
|
||||
attr_accessor :thread
|
||||
|
||||
class WebConsolePipe < Rex::IO::BidirectionalPipe
|
||||
|
||||
attr_accessor :input
|
||||
attr_accessor :output
|
||||
attr_accessor :prompt
|
||||
attr_accessor :killed
|
||||
|
||||
def intrinsic_shell?
|
||||
true
|
||||
end
|
||||
|
||||
def supports_readline
|
||||
false
|
||||
end
|
||||
|
||||
def _print_prompt
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Wrapper methods around input pipe
|
||||
#
|
||||
|
||||
|
||||
def close
|
||||
self.pipe_input.close
|
||||
end
|
||||
|
||||
def put(*args)
|
||||
self.pipe_input.put(*args)
|
||||
end
|
||||
|
||||
def gets
|
||||
self.pipe_input.gets
|
||||
end
|
||||
|
||||
def pgets
|
||||
self.pipe_input.gets
|
||||
end
|
||||
|
||||
def eof?
|
||||
self.pipe_input.eof?
|
||||
end
|
||||
|
||||
def fd(*args)
|
||||
raise ::RuntimeError, "Session interaction should be performed via the Sessions tab"
|
||||
self.pipe_input.fd(*args)
|
||||
end
|
||||
|
||||
def sysread(*args)
|
||||
self.pipe_input.sysread(*args)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Provides some overrides for web-based consoles
|
||||
#
|
||||
module WebConsoleShell
|
||||
|
||||
def supports_color?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(framework, console_id)
|
||||
# Configure the framework
|
||||
self.framework = framework
|
||||
|
||||
# Configure the ID
|
||||
self.console_id = console_id
|
||||
|
||||
# Create a new pipe
|
||||
self.pipe = WebConsolePipe.new
|
||||
self.pipe.input = self.pipe.pipe_input
|
||||
|
||||
# Create a read subscriber
|
||||
self.pipe.create_subscriber('msfweb')
|
||||
|
||||
# Initialize the console with our pipe
|
||||
self.console = Msf::Ui::Console::Driver.new(
|
||||
'msf',
|
||||
'>',
|
||||
{
|
||||
'Framework' => self.framework,
|
||||
'LocalInput' => self.pipe,
|
||||
'LocalOutput' => self.pipe,
|
||||
'AllowCommandPassthru' => false,
|
||||
}
|
||||
)
|
||||
|
||||
self.console.extend(WebConsoleShell)
|
||||
|
||||
self.thread = Thread.new { self.console.run }
|
||||
|
||||
update_access()
|
||||
end
|
||||
|
||||
def update_access
|
||||
self.last_access = Time.now
|
||||
end
|
||||
|
||||
def read
|
||||
update_access
|
||||
|
||||
self.pipe.read_subscriber('msfweb')
|
||||
end
|
||||
|
||||
def write(buf)
|
||||
update_access
|
||||
self.pipe.write_input(buf)
|
||||
end
|
||||
|
||||
def execute(cmd)
|
||||
self.console.run_single(cmd)
|
||||
end
|
||||
|
||||
def prompt
|
||||
self.pipe.prompt
|
||||
end
|
||||
|
||||
def tab_complete(cmd)
|
||||
self.console.tab_complete(cmd)
|
||||
end
|
||||
|
||||
def shutdown
|
||||
self.pipe.killed = true
|
||||
self.pipe.close
|
||||
self.thread.kill
|
||||
end
|
||||
end
|
||||
|
||||
###
|
||||
#
|
||||
|
@ -164,6 +21,7 @@ class Driver < Msf::Ui::Driver
|
|||
|
||||
attr_accessor :framework # :nodoc:
|
||||
attr_accessor :consoles # :nodoc:
|
||||
attr_accessor :sessions # :nodoc:
|
||||
attr_accessor :last_console # :nodoc:
|
||||
|
||||
ConfigCore = "framework/core"
|
||||
|
@ -181,8 +39,8 @@ class Driver < Msf::Ui::Driver
|
|||
# Set the passed options hash for referencing later on.
|
||||
self.opts = opts
|
||||
|
||||
# Initalize the consoles set
|
||||
self.consoles = {}
|
||||
self.sessions = {}
|
||||
|
||||
# Initialize configuration
|
||||
Msf::Config.init
|
||||
|
@ -195,10 +53,6 @@ class Driver < Msf::Ui::Driver
|
|||
|
||||
# Initialize the console count
|
||||
self.last_console = 0
|
||||
|
||||
# Give the comm an opportunity to set up so that it can receive
|
||||
# notifications about session creation and so on.
|
||||
# Comm.setup(framework)
|
||||
end
|
||||
|
||||
def create_console
|
||||
|
@ -228,6 +82,48 @@ class Driver < Msf::Ui::Driver
|
|||
end
|
||||
end
|
||||
|
||||
def write_session(id, buf)
|
||||
ses = self.framework.sessions[id]
|
||||
return if not ses
|
||||
ses.user_input.put(buf)
|
||||
end
|
||||
|
||||
def read_session(id)
|
||||
ses = self.framework.sessions[id]
|
||||
return if not ses
|
||||
ses.user_output.read_subscriber('session_reader')
|
||||
end
|
||||
|
||||
# Detach the session from an existing input/output pair
|
||||
def connect_session(id)
|
||||
|
||||
# Ignore invalid sessions
|
||||
ses = self.framework.sessions[id]
|
||||
return if not ses
|
||||
|
||||
# Has this session already been detached?
|
||||
return if ses.user_output.has_subscriber?('session_reader')
|
||||
|
||||
# Create a new pipe
|
||||
spipe = WebConsole::WebConsolePipe.new
|
||||
spipe.input = spipe.pipe_input
|
||||
|
||||
# Create a read subscriber
|
||||
spipe.create_subscriber('session_reader')
|
||||
|
||||
# Replace the input/output handles
|
||||
ses.user_input = spipe.input
|
||||
ses.user_output = spipe
|
||||
|
||||
Thread.new do
|
||||
ses.interact
|
||||
end
|
||||
end
|
||||
|
||||
def sessions
|
||||
self.framework.sessions
|
||||
end
|
||||
|
||||
#
|
||||
# Stub
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue