Session detach support, closer to clean hand-off between session -d / session -i. Make autovnc look for both vncviewer and vncviewer.exe
git-svn-id: file:///home/svn/framework3/trunk@4424 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
a4b06e1653
commit
80c4bcd5ab
|
@ -33,6 +33,10 @@ class ConsoleController < ApplicationController
|
|||
out = out.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
pro = console.prompt.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
|
||||
if (console.busy)
|
||||
pro = '(running)'.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
end
|
||||
|
||||
script = "// Metasploit Web Console Data\n"
|
||||
script += "var con_prompt = unescape('#{pro}');\n"
|
||||
script += "var con_update = unescape('#{out}');\n"
|
||||
|
@ -66,7 +70,11 @@ class ConsoleController < ApplicationController
|
|||
|
||||
out = out.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
pro = @console.prompt.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
|
||||
|
||||
if (@console.busy)
|
||||
pro = '(running)'.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
end
|
||||
|
||||
script = "// Metasploit Web Console Data\n"
|
||||
script += "var con_prompt = unescape('#{pro}');\n"
|
||||
script += "var con_update = unescape('#{out}');\n"
|
||||
|
@ -79,7 +87,7 @@ class ConsoleController < ApplicationController
|
|||
cmdl = params[:tab]
|
||||
out = ""
|
||||
|
||||
if (params[:tab].strip.length > 0)
|
||||
if (not @console.busy and params[:tab].strip.length > 0)
|
||||
opts = @console.tab_complete(params[:tab]) || []
|
||||
end
|
||||
|
||||
|
@ -108,14 +116,18 @@ class ConsoleController < ApplicationController
|
|||
cmdl = cmd_top[0, depth]
|
||||
end
|
||||
|
||||
out = "\n" + opts.map{ |c| " >> " + c }.join("\n")
|
||||
out = "\n" + opts.map{ |c| ">> " + c }.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
out = out.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
pro = @console.prompt.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
tln = cmdl.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
|
||||
|
||||
if (@console.busy)
|
||||
pro = '(running)'.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
end
|
||||
|
||||
script = "// Metasploit Web Console Data\n"
|
||||
script += "var con_prompt = unescape('#{pro}');\n"
|
||||
script += "var con_update = unescape('#{out}');\n"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
|
||||
<meta name="Author" content="LMH (lmh@info-pull.com)" />
|
||||
<meta name="Copyright" content="(c) 2006, LMH (lmh@info-pull.com)" />
|
||||
<title>msfweb v.3 - console demo</title>
|
||||
<title>Metasploit Console</title>
|
||||
<% ["prototype","effects","controls", "window", "application", "console"].each do |js| %>
|
||||
<%= javascript_include_tag js %><% end %>
|
||||
<%= stylesheet_link_tag "msfconsole" %>
|
||||
|
|
|
@ -127,7 +127,7 @@ function console_keypress(e) {
|
|||
console_hindex = console_history.length - 1;
|
||||
}
|
||||
|
||||
console_printline("\n" + con_prompt + ' ' + console_input.value, 'output_line')
|
||||
console_printline("\n>> " + console_input.value + "\n\n", 'output_line')
|
||||
|
||||
if(cmd_internal[console_input.value]) {
|
||||
cmd_internal[console_input.value]();
|
||||
|
|
|
@ -67,6 +67,7 @@ html,body {
|
|||
|
||||
#console_command_bar {
|
||||
background: #000000;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
#console_status {
|
||||
|
|
|
@ -126,7 +126,11 @@ class VncInject
|
|||
# Launches VNC viewer against the local relay for this VNC server session.
|
||||
#
|
||||
def autovnc
|
||||
if (Rex::FileUtils::find_full_path('vncviewer'))
|
||||
vnc =
|
||||
Rex::FileUtils::find_full_path('vncviewer') ||
|
||||
Rex::FileUtils::find_full_path('vncviewer.exe')
|
||||
|
||||
if (vnc)
|
||||
Thread.new {
|
||||
system("vncviewer #{vlhost}::#{vlport}")
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ class Core
|
|||
"-l" => [ false, "List all active sessions." ],
|
||||
"-v" => [ false, "List verbose fields." ],
|
||||
"-q" => [ false, "Quiet mode." ],
|
||||
"-d" => [ true, "Detach an interactive session" ],
|
||||
"-k" => [ true, "Terminate session." ])
|
||||
|
||||
@@jobs_opts = Rex::Parser::Arguments.new(
|
||||
|
@ -623,6 +624,10 @@ class Core
|
|||
when "-k"
|
||||
method = 'kill'
|
||||
sid = val
|
||||
|
||||
when "-d"
|
||||
method = 'detach'
|
||||
sid = val
|
||||
|
||||
# Display help banner
|
||||
when "-h"
|
||||
|
@ -639,9 +644,18 @@ class Core
|
|||
|
||||
when 'kill'
|
||||
if ((session = framework.sessions.get(sid)))
|
||||
print_status("Killing session #{sid}")
|
||||
session.kill
|
||||
end
|
||||
|
||||
|
||||
when 'detach'
|
||||
if ((session = framework.sessions.get(sid)))
|
||||
print_status("Detaching session #{sid}")
|
||||
if (session.interactive?)
|
||||
session.detach()
|
||||
end
|
||||
end
|
||||
|
||||
when 'interact'
|
||||
if ((session = framework.sessions.get(sid)))
|
||||
if (session.interactive?)
|
||||
|
@ -654,13 +668,9 @@ class Core
|
|||
|
||||
# Interact
|
||||
session.interact()
|
||||
|
||||
# Once interact returns, swap the output handle with a
|
||||
# none output
|
||||
#
|
||||
# TODO: change this to use buffered output so we can call
|
||||
# flush later on
|
||||
session.reset_ui
|
||||
|
||||
self.active_session = nil
|
||||
|
||||
else
|
||||
print_error("Session #{sid} is non-interactive.")
|
||||
end
|
||||
|
|
|
@ -77,7 +77,6 @@ class WebConsole
|
|||
|
||||
def read
|
||||
update_access
|
||||
|
||||
self.pipe.read_subscriber('msfweb')
|
||||
end
|
||||
|
||||
|
@ -102,6 +101,10 @@ class WebConsole
|
|||
self.pipe.close
|
||||
self.thread.kill
|
||||
end
|
||||
|
||||
def busy
|
||||
self.console.busy
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -100,17 +100,20 @@ class Driver < Msf::Ui::Driver
|
|||
# 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')
|
||||
|
||||
# Detach session if necessary
|
||||
ses.detach()
|
||||
|
||||
# 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
|
||||
|
|
|
@ -21,7 +21,14 @@ module Interactive
|
|||
# rstream to user_output.
|
||||
#
|
||||
def interact
|
||||
|
||||
# Prevent two thread from interacting at once
|
||||
if(self.interacting)
|
||||
raise RuntimeError, "This session is already interacting with another console"
|
||||
end
|
||||
|
||||
self.interacting = true
|
||||
self.completed = false
|
||||
|
||||
eof = false
|
||||
|
||||
|
@ -53,25 +60,52 @@ module Interactive
|
|||
break if eof
|
||||
end
|
||||
|
||||
begin
|
||||
|
||||
# Restore the suspend handler
|
||||
restore_suspend
|
||||
|
||||
# If we've hit eof, call the interact complete handler
|
||||
_interact_complete if (eof == true)
|
||||
# Restore the suspend handler
|
||||
restore_suspend
|
||||
|
||||
# Shutdown the readline thread
|
||||
# XXX disabled
|
||||
# user_input.readline_stop() if user_input.supports_readline
|
||||
# If we've hit eof, call the interact complete handler
|
||||
_interact_complete if (eof == true)
|
||||
|
||||
# Shutdown the readline thread
|
||||
# XXX disabled
|
||||
# user_input.readline_stop() if user_input.supports_readline
|
||||
|
||||
# Detach from the input/output handles
|
||||
reset_ui()
|
||||
|
||||
ensure
|
||||
# Mark this as completed
|
||||
self.completed = true
|
||||
end
|
||||
|
||||
# Return whether or not EOF was reached
|
||||
return eof
|
||||
end
|
||||
|
||||
#
|
||||
# Stops the current interaction
|
||||
#
|
||||
def detach
|
||||
if (self.interacting)
|
||||
self.interacting = false
|
||||
stime = Time.now.to_f
|
||||
while(Time.now.to_f > stime + 5 and not self.completed)
|
||||
select(nil, nil, nil, 0.10)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Whether or not the session is currently being interacted with
|
||||
#
|
||||
attr_accessor :interacting
|
||||
|
||||
#
|
||||
# Whether or not the session has completed interaction
|
||||
#
|
||||
attr_accessor :completed
|
||||
|
||||
protected
|
||||
|
||||
|
@ -144,9 +178,10 @@ protected
|
|||
# writing it to the other. Both are expected to implement Rex::IO::Stream.
|
||||
#
|
||||
def interact_stream(stream)
|
||||
while self.interacting
|
||||
while self.interacting
|
||||
|
||||
# Select input and rstream
|
||||
sd = Rex::ThreadSafe.select([ _local_fd, _remote_fd(stream) ])
|
||||
sd = Rex::ThreadSafe.select([ _local_fd, _remote_fd(stream) ], nil, nil, 0.25)
|
||||
|
||||
# Cycle through the items that have data
|
||||
# From the stream? Write to user_output.
|
||||
|
|
|
@ -226,7 +226,9 @@ module DispatcherShell
|
|||
# Runs the supplied command on the given dispatcher.
|
||||
#
|
||||
def run_command(dispatcher, method, arguments)
|
||||
self.busy = true
|
||||
dispatcher.send('cmd_' + method, *arguments)
|
||||
self.busy = false
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -321,6 +323,7 @@ module DispatcherShell
|
|||
|
||||
attr_accessor :dispatcher_stack # :nodoc:
|
||||
attr_accessor :tab_words # :nodoc:
|
||||
attr_accessor :busy # :nodoc:
|
||||
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue