334 lines
8.5 KiB
Ruby
334 lines
8.5 KiB
Ruby
module Msf
|
|
module Ui
|
|
module Gtk2
|
|
|
|
###
|
|
#
|
|
# Classic console herited from Gtk::Window
|
|
#
|
|
###
|
|
class SkeletonConsole < Gtk::Window
|
|
require 'rex/io/bidirectional_pipe'
|
|
include Msf::Ui::Gtk2::MyControls
|
|
|
|
###
|
|
#
|
|
# Basic command history class
|
|
#
|
|
###
|
|
class History
|
|
|
|
def initialize
|
|
@history = [""]
|
|
@position = @history.length - 1
|
|
end
|
|
|
|
#
|
|
# Get previous command in history array
|
|
#
|
|
def prev(current)
|
|
l = current
|
|
l = l[0,1] if (l.length > 0 and l[0,1] == '\n')
|
|
l = l[-1,1] if (l.length > 0 and l[-1,1] == '\n')
|
|
if (@position > 0)
|
|
if (@position == (@history.length - 1))
|
|
@history[@history.length - 1] = l
|
|
end
|
|
@position = @position - 1
|
|
return @history[@position]
|
|
end
|
|
return current
|
|
end
|
|
|
|
#
|
|
# Get next command in history array
|
|
#
|
|
def next(current)
|
|
if (@position < @history.length - 1)
|
|
@position = @position + 1
|
|
return @history[@position]
|
|
end
|
|
return current
|
|
end
|
|
|
|
#
|
|
# Append a new command to history
|
|
#
|
|
def append(cmd)
|
|
@position = @history.length - 1
|
|
return if cmd.length == 0
|
|
if ( (@position == 0) or (@position > 0 and cmd != @history[@position - 1]) )
|
|
@history[@position] = cmd
|
|
@position = @position + 1
|
|
@history.push('')
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
ID_SESSION, PEER, TYPE, O_SESSION, O_BUFFER = *(0..5).to_a
|
|
@@offset = 0
|
|
|
|
attr_accessor :type, :button_close
|
|
|
|
#
|
|
# Init the SkeletonConsole class
|
|
#
|
|
def initialize(iter)
|
|
# Style
|
|
console_style = File.join(driver.resource_directory, 'style', 'console.rc')
|
|
Gtk::RC.parse(console_style)
|
|
|
|
# Call the parent
|
|
super(Gtk::Window::TOPLEVEL)
|
|
|
|
# initialize the session var from the iter sessions tree
|
|
@session = iter[O_SESSION]
|
|
|
|
# Layout stuff
|
|
self.set_default_size(500, 400)
|
|
self.set_border_width(10)
|
|
|
|
# Set title with the tunnel peer
|
|
self.set_title(@session.tunnel_peer)
|
|
|
|
# Add a vertical box to the window
|
|
vbox = Gtk::VBox.new(false, 5)
|
|
self.add(vbox)
|
|
|
|
# Setup text view and buffer
|
|
@textview = Gtk::TextView.new
|
|
if iter[O_BUFFER].nil?
|
|
@buffer = Gtk::TextBuffer.new
|
|
iter[O_BUFFER] = @buffer
|
|
else
|
|
@buffer = iter[O_BUFFER]
|
|
end
|
|
scrolled_window = Gtk::ScrolledWindow.new
|
|
scrolled_window.add(@textview)
|
|
vbox.pack_start(scrolled_window, true, true, 5)
|
|
scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC)
|
|
|
|
# Setup text buffer
|
|
@textview.set_buffer(@buffer)
|
|
@textview.editable = true
|
|
@textview.set_cursor_visible(true)
|
|
@buffer.create_mark('end_mark', @buffer.end_iter, false)
|
|
|
|
# Setup button close
|
|
hbox = Gtk::HButtonBox.new
|
|
hbox.layout_style = Gtk::ButtonBox::END
|
|
@button_close = Gtk::Button.new(Gtk::Stock::CLOSE)
|
|
|
|
# Pack
|
|
hbox.pack_end(@button_close, false, false, 5)
|
|
vbox.pack_start(hbox, false, false, 0)
|
|
|
|
# Signal for the Return key pressed
|
|
signal_connect('key_press_event') do |edit, event|
|
|
on_key_pressed(event)
|
|
end
|
|
|
|
# Create the pipe interface
|
|
@pipe = Rex::IO::BidirectionalPipe.new
|
|
|
|
# Start the session interaction
|
|
@t_run = Thread.new do
|
|
@session.interact(@pipe, @pipe)
|
|
end
|
|
|
|
# Create a subscriber with a callback for the UI
|
|
@sid = @pipe.create_subscriber_proc() do |data|
|
|
insert_text(Rex::Text.to_utf8(data))
|
|
end
|
|
|
|
# Init an history object
|
|
@historic = History.new()
|
|
|
|
# Init the prompt variable with the session type
|
|
@type = @session.type
|
|
|
|
# Display all
|
|
self.show_all
|
|
|
|
end #intialize
|
|
|
|
#
|
|
# Send command to bidirectionnal_pipe
|
|
#
|
|
def send_cmd(cmd)
|
|
# What time is it ?
|
|
# update_access
|
|
|
|
# Write the command plus a newline to the input
|
|
@pipe.write_input(cmd + "\n")
|
|
end
|
|
|
|
#
|
|
# Just close the console, not kill !
|
|
#
|
|
def close_console
|
|
self.destroy
|
|
end
|
|
|
|
###########
|
|
protected #
|
|
###########
|
|
|
|
#
|
|
# update access
|
|
#
|
|
def update_access
|
|
last_access = Time.now
|
|
end
|
|
|
|
#
|
|
# meterpreter prompt
|
|
#
|
|
def prompt
|
|
null_prompt = ""
|
|
meta_prompt = "meterpreter >> "
|
|
if (@type == "meterpreter")
|
|
@buffer.insert(@buffer.end_iter, meta_prompt)
|
|
else
|
|
@buffer.insert(@buffer.end_iter, null_prompt)
|
|
end
|
|
@@offset = @buffer.end_iter.offset
|
|
end
|
|
|
|
#
|
|
# Get the current line
|
|
#
|
|
def current_line
|
|
# get the actual offset
|
|
start = @buffer.get_iter_at_offset(@@offset)
|
|
|
|
# get the command
|
|
line = @buffer.get_text(start, @buffer.end_iter)
|
|
|
|
return line
|
|
end
|
|
|
|
#
|
|
# Replace the current active line with another line
|
|
#
|
|
def replace(line)
|
|
# get the actual offset
|
|
start = @buffer.get_iter_at_offset(@@offset)
|
|
|
|
# Delete all
|
|
@buffer.delete(start, @buffer.end_iter)
|
|
|
|
# Save the new offset
|
|
@@offset = @buffer.end_iter.offset
|
|
|
|
# insert the old command
|
|
@buffer.insert(@buffer.end_iter, line)
|
|
end
|
|
|
|
#
|
|
# Catch the text from the textview
|
|
#
|
|
def catch_text
|
|
# get the actual offset
|
|
start = @buffer.get_iter_at_offset(@@offset)
|
|
|
|
# get the command
|
|
cmd = @buffer.get_text(start, @buffer.end_iter)
|
|
|
|
# Save the command to the history object
|
|
@historic.append(cmd)
|
|
|
|
# Write the command to our pipe
|
|
send_cmd(cmd)
|
|
|
|
# Add a return line to our buffer
|
|
insert_text("\n")
|
|
|
|
# Call the prompt
|
|
prompt()
|
|
|
|
# Create the mark tag if not exist
|
|
if (not @buffer.get_mark('end_mark'))
|
|
@buffer.create_mark('end_mark', @buffer.end_iter, false)
|
|
end
|
|
|
|
# Save our offset
|
|
@@offset = @buffer.end_iter.offset
|
|
end
|
|
|
|
#
|
|
# Insert the text into the buffer
|
|
#
|
|
def insert_text(text)
|
|
# Create the mark tag if not exist
|
|
@buffer.insert(@buffer.end_iter, text)
|
|
if (not @buffer.get_mark('end_mark'))
|
|
@buffer.create_mark('end_mark', @buffer.end_iter, false)
|
|
end
|
|
|
|
# Save our offset
|
|
@@offset = @buffer.end_iter.offset
|
|
|
|
# Scrolled the view until the end of the buffer
|
|
@textview.scroll_mark_onscreen(@buffer.get_mark('end_mark'))
|
|
end
|
|
|
|
#
|
|
# A key pressed handler
|
|
#
|
|
def on_key_pressed(event)
|
|
|
|
# Enter key
|
|
if (event.keyval == Gdk::Keyval::GDK_Return)
|
|
catch_text()
|
|
|
|
# Backspace key
|
|
elsif (event.keyval == Gdk::Keyval::GDK_BackSpace)
|
|
iter = @buffer.end_iter
|
|
if iter.offset == @@offset
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
|
|
# Delete key
|
|
elsif (event.keyval == Gdk::Keyval::GDK_Delete)
|
|
iter = @buffer.end_iter
|
|
if iter.offset == @@offset
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
|
|
# Previous command
|
|
elsif (event.keyval == Gdk::Keyval::GDK_Up)
|
|
cmd = @historic.prev(current_line())
|
|
replace(cmd)
|
|
return true
|
|
|
|
# Next command
|
|
elsif (event.keyval == Gdk::Keyval::GDK_Down)
|
|
cmd = @historic.next(current_line())
|
|
replace(cmd)
|
|
return true
|
|
end
|
|
|
|
end
|
|
|
|
end # SkeletonConsole
|
|
|
|
###
|
|
#
|
|
# This class surcharge the Rex::IO::BidirectionalPipe *original* behaviour
|
|
#
|
|
###
|
|
class GtkConsolePipe < Rex::IO::BidirectionalPipe
|
|
def prompting?
|
|
false
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
end |