Tab completion has been added to the web console
git-svn-id: file:///home/svn/framework3/trunk@4290 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
951a91d32c
commit
8d06aad5b4
|
@ -20,11 +20,71 @@ class ConsoleController < ApplicationController
|
|||
@console = $msfweb.consoles[@cid]
|
||||
|
||||
if(params[:cmd])
|
||||
out = ''
|
||||
|
||||
if (params[:cmd].strip.length > 0)
|
||||
@console.write(params[:cmd] + "\n")
|
||||
out = @console.execute(params[:cmd])
|
||||
end
|
||||
send_data(@console.read(), :type => "application/octet-stream")
|
||||
|
||||
out = out.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
pro = @console.prompt.unpack('C*').map{|c| sprintf("%%%.2x", c)}.join
|
||||
|
||||
script = "// Metasploit Web Console Data\n"
|
||||
script += "var con_prompt = unescape('#{pro}');\n"
|
||||
script += "var con_update = unescape('#{out}');\n"
|
||||
|
||||
send_data(script, :type => "text/javascript")
|
||||
end
|
||||
|
||||
if(params[:tab])
|
||||
opts = []
|
||||
cmdl = params[:tab]
|
||||
out = ""
|
||||
|
||||
if (params[:tab].strip.length > 0)
|
||||
opts = @console.tab_complete(params[:tab]) || []
|
||||
end
|
||||
|
||||
if (opts.length == 1)
|
||||
cmdl = opts[0]
|
||||
else
|
||||
if (opts.length == 0)
|
||||
# aint got nothin
|
||||
else
|
||||
|
||||
cmd_top = opts[0]
|
||||
depth = 0
|
||||
|
||||
while (depth < cmd_top.length)
|
||||
match = true
|
||||
opts.each do |line|
|
||||
next if line[depth] == cmd_top[depth]
|
||||
match = false
|
||||
break
|
||||
end
|
||||
break if not match
|
||||
depth += 1
|
||||
end
|
||||
|
||||
if (depth > 0)
|
||||
cmdl = cmd_top[0, depth]
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
script = "// Metasploit Web Console Data\n"
|
||||
script += "var con_prompt = unescape('#{pro}');\n"
|
||||
script += "var con_update = unescape('#{out}');\n"
|
||||
script += "var con_tabbed = unescape('#{tln}');\n"
|
||||
|
||||
send_data(script, :type => "text/javascript")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -22,19 +22,29 @@
|
|||
</div>
|
||||
</pre>
|
||||
|
||||
<textarea
|
||||
rows="1"
|
||||
id="console_prompt"
|
||||
class="prompt"
|
||||
disabled="true"
|
||||
></textarea>
|
||||
<textarea
|
||||
<table class="console_command_bar" border=0 padding=4 cellspacing=0 width='100%'>
|
||||
<tr>
|
||||
<td
|
||||
nowrap='true'
|
||||
valign='top'
|
||||
id="console_prompt"
|
||||
>
|
||||
<%=h @console.prompt %>
|
||||
</td>
|
||||
<td nowrap='true' width='100%'>
|
||||
|
||||
<textarea
|
||||
id="console_input"
|
||||
class="input"
|
||||
wrap="off"
|
||||
onkeydown="return console_keydown(event)"
|
||||
onkeydown="return console_keydown(event)"
|
||||
onkeypress="return console_keypress(event)"
|
||||
rows="1"
|
||||
></textarea>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -10,6 +10,12 @@ var console_input; // Object to console input
|
|||
var console_output; // Object to console output
|
||||
var console_prompt; // Object to console prompt
|
||||
|
||||
// Placeholders
|
||||
var con_prompt = "";
|
||||
var con_update = "";
|
||||
var con_tabbed = "";
|
||||
|
||||
|
||||
function console_refocus() {
|
||||
console_input.blur();
|
||||
console_input.focus();
|
||||
|
@ -25,46 +31,36 @@ function console_printline(s, type) {
|
|||
}
|
||||
}
|
||||
|
||||
var prompt = 'msf> ';
|
||||
var console_commands = {
|
||||
print : function print(s) {
|
||||
console_printline(s, "info");
|
||||
},
|
||||
clear: function clear() {
|
||||
var child_preserve = 3;
|
||||
while (console_output.childNodes[child_preserve])
|
||||
console_output.removeChild(console_output.childNodes[child_preserve]);
|
||||
}
|
||||
}
|
||||
|
||||
function console_tabcomplete() {
|
||||
// TODO: get console_input.value, send to process_cmd with mode=tabcomplete
|
||||
// retrieve array of possible matches
|
||||
// put them to output container
|
||||
// done.
|
||||
}
|
||||
|
||||
function console_execute() {
|
||||
if (console_commands[console_input.value]) {
|
||||
f = console_commands[console_input.value];
|
||||
alert(f);
|
||||
}
|
||||
}
|
||||
|
||||
function console_update_output(req) {
|
||||
console_printline(req.responseText);
|
||||
console_input.focus();
|
||||
|
||||
try { eval(req.responseText); } catch(e){ alert(req.responseText); }
|
||||
|
||||
window.status = "";
|
||||
|
||||
console_printline(con_update);
|
||||
console_prompt.innerHTML = con_prompt;
|
||||
console_refocus();
|
||||
|
||||
}
|
||||
|
||||
function console_keydown(e) {
|
||||
function console_update_tabs(req) {
|
||||
try { eval(req.responseText); } catch(e){ console_output.innerHTML = req.responseText; }
|
||||
|
||||
window.status = "";
|
||||
console_printline(con_update);
|
||||
console_prompt.innerHTML = con_prompt;
|
||||
console_input.value = con_tabbed;
|
||||
|
||||
console_refocus();
|
||||
}
|
||||
|
||||
if (e.keyCode == 8) {
|
||||
window.title = console_input.value;
|
||||
}
|
||||
|
||||
if (e.keyCode == 13) { // enter
|
||||
function console_keypress(e) {
|
||||
if (e.keyCode == 13) { // enter
|
||||
console_history.push(console_input.value);
|
||||
try { console_execute(); } catch(er) { alert(er); };
|
||||
|
||||
console_printline("\n" + con_prompt + ' ' + console_input.value)
|
||||
|
||||
window.status = "Executing command, please wait..."
|
||||
|
||||
new Ajax.Updater("console_update", document.location, {
|
||||
asynchronous:true,
|
||||
|
@ -72,19 +68,31 @@ function console_keydown(e) {
|
|||
parameters:"cmd=" + escape(console_input.value),
|
||||
onComplete:console_update_output
|
||||
});
|
||||
|
||||
|
||||
console_input.value = "";
|
||||
console_input.focus();
|
||||
console_prompt = prompt;
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (e.keyCode == 38) { // up
|
||||
}
|
||||
|
||||
|
||||
function console_keydown(e) {
|
||||
|
||||
if (e.keyCode == 38) { // up
|
||||
// TODO: place upper cmd in history on console_input.value
|
||||
alert('UP');
|
||||
} else if (e.keyCode == 40) { // down
|
||||
// TODO: place lower cmd in history on console_input.value
|
||||
alert('DOWN');
|
||||
} else if (e.keyCode == 9) { // tab
|
||||
console_tabcomplete();
|
||||
setTimeout(function() { console_refocus(); }, 0);
|
||||
window.status = "Finding possible commands..."
|
||||
new Ajax.Updater("console_update", document.location, {
|
||||
asynchronous:true,
|
||||
evalScripts:true,
|
||||
parameters:"tab=" + escape(console_input.value),
|
||||
onComplete:console_update_tabs
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -95,8 +103,8 @@ function console_init() {
|
|||
console_output = document.getElementById("console_output");
|
||||
console_prompt = document.getElementById("console_prompt");
|
||||
|
||||
console_prompt.value = prompt;
|
||||
console_input.focus();
|
||||
console_refocus();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ html,body {
|
|||
}
|
||||
|
||||
#console_window {
|
||||
width: 100%;
|
||||
margin: 1em;
|
||||
background: #000000;
|
||||
padding: 1em;
|
||||
|
@ -37,22 +36,19 @@ html,body {
|
|||
}
|
||||
|
||||
.input {
|
||||
border: none;
|
||||
font: inherit;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
padding: 0;
|
||||
margin-top: 1em;
|
||||
background: #000000;
|
||||
border: 0;
|
||||
color: white;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.prompt {
|
||||
width: 3em;
|
||||
margin-top: 1em;
|
||||
border: none;
|
||||
padding: 0;
|
||||
background: #000000;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.console_command_bar {
|
||||
background: #000000;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ class WebConsole
|
|||
attr_accessor :console_id
|
||||
attr_accessor :last_access
|
||||
attr_accessor :framework
|
||||
|
||||
attr_accessor :thread
|
||||
|
||||
class WebConsolePipe < Rex::IO::BidirectionalPipe
|
||||
|
||||
|
@ -29,7 +29,7 @@ class WebConsole
|
|||
attr_accessor :output
|
||||
attr_accessor :prompt
|
||||
attr_accessor :killed
|
||||
|
||||
|
||||
def eof?
|
||||
self.pipe_input.eof?
|
||||
end
|
||||
|
@ -67,7 +67,7 @@ class WebConsole
|
|||
|
||||
# Initialize the console with our pipe
|
||||
self.console = Msf::Ui::Console::Driver.new(
|
||||
'msf>',
|
||||
'msf',
|
||||
'>',
|
||||
{
|
||||
'Framework' => self.framework,
|
||||
|
@ -76,7 +76,7 @@ class WebConsole
|
|||
}
|
||||
)
|
||||
|
||||
Thread.new { self.console.run }
|
||||
self.thread = Thread.new { self.console.run }
|
||||
|
||||
update_access()
|
||||
end
|
||||
|
@ -95,9 +95,24 @@ class WebConsole
|
|||
self.pipe.write_input(buf)
|
||||
end
|
||||
|
||||
def execute(cmd)
|
||||
self.console.run_single(cmd)
|
||||
self.read
|
||||
end
|
||||
|
||||
def prompt
|
||||
$stderr.puts(self.pipe.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
|
||||
|
||||
|
|
|
@ -49,6 +49,25 @@ class BidirectionalPipe < Rex::Ui::Text::Input
|
|||
buf.print(msg)
|
||||
}
|
||||
end
|
||||
|
||||
def print_error(msg)
|
||||
print_line('[-] ' + msg)
|
||||
end
|
||||
|
||||
def print_line(msg)
|
||||
print(msg + "\n")
|
||||
end
|
||||
|
||||
def print_good(msg)
|
||||
print_line('[+] ' + msg)
|
||||
end
|
||||
|
||||
def flush
|
||||
end
|
||||
|
||||
def print_status(msg)
|
||||
print_line('[*] ' + msg)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
|
|
Loading…
Reference in New Issue