meterp fs wrapper action rockin the house

git-svn-id: file:///home/svn/incoming/trunk@2793 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Matt Miller 2005-07-18 07:46:54 +00:00
parent 45b1e69210
commit 9a420ac750
13 changed files with 387 additions and 22 deletions

View File

@ -16,7 +16,9 @@ class DataStore < Hash
#
def import_options(options)
options.each_option { |name, opt|
if (opt.default)
# If the option has a default value, import it, but only if the
# datastore doesn't already have a value set for it.
if (opt.default and self[name] == nil)
self.store(name, opt.default.to_s)
end
}
@ -130,14 +132,26 @@ class ModuleDataStore < DataStore
# if we can't directly find it
#
def fetch(key)
val = super || @_module.framework.datastore[key]
val = super
if (!val and @_module and @_module.framework)
val = @_module.framework.datastore[key]
end
return val
end
#
# Same as fetch
#
def [](key)
val = super || @_module.framework.datastore[key]
val = super
if (!val and @_module and @_module.framework)
val = @_module.framework.datastore[key]
end
return val
end
end

View File

@ -129,7 +129,7 @@ class Payload < Msf::Module
# Generates the payload and return the raw buffer
#
def generate
raw = payload
raw = payload.dup
# If the payload is generated and there are offsets to substitute,
# do that now.

View File

@ -46,7 +46,7 @@ module Msf::Payload::Stager
# Transmit the associated stage.
#
def handle_connection(conn)
p = stage_payload
p = stage_payload.dup
substitute_vars(p, stage_offsets) if (stage_offsets)

View File

@ -47,7 +47,7 @@ module Msf::Payload::Windows
method = datastore[name]
method = 'seh' if (!method or @@exit_types.include?(method) == false)
raw[offset, 4] = [ @@exit_types[method] ].pack('V')
raw[offset, 4] = [ @@exit_types[method] ].pack(pack || 'V')
return true
end

View File

@ -1,4 +1,5 @@
module Rex
Root = File.join(File.dirname(__FILE__), 'rex')
end
# Generic classes

View File

@ -14,6 +14,12 @@ module Rex
module Post
module Meterpreter
#
# Just to get it in there...
#
module Extensions
end
###
#
# Client
@ -89,11 +95,18 @@ class Client
# Loads the client half of the supplied extension and initializes it as a
# registered extension that can be reached through client.ext.[extension].
def add_extension(name)
old = Rex::Post::Meterpreter::Extensions.constants
require("rex/post/meterpreter/extensions/#{name.downcase}/#{name.downcase}")
new = Rex::Post::Meterpreter::Extensions.constants
# No new constants added?
if ((diff = new - old).empty?)
return false
end
# XXX might want to be safer and catch the exception here?
# maybe not since we are just going to reraise right away...
ext = Rex::Post::Meterpreter::Extensions.const_get(name).const_get(name).new(self)
ext = Rex::Post::Meterpreter::Extensions.const_get(diff[0]).const_get(diff[0]).new(self)
self.ext.aliases[ext.name] = ext

View File

@ -48,7 +48,7 @@ class Dir < Rex::Post::Dir
end
# Enumerates all of the files/folders in a given directory.
def Dir.entries(name)
def Dir.entries(name = getwd)
request = Packet.create_request('stdapi_fs_ls')
files = []
@ -134,7 +134,7 @@ class Dir < Rex::Post::Dir
# Downloads the contents of a remote directory a
# local directory, optionally in a recursive fashion.
def Dir.download(dst, src, recursive = false)
def Dir.download(dst, src, recursive = false, &stat)
self.entries(src).each { |src_sub|
dst_item = dst + ::File::SEPARATOR + src_sub
src_item = src + File::SEPARATOR + src_sub
@ -146,7 +146,9 @@ class Dir < Rex::Post::Dir
src_stat = client.fs.filestat.new(src_item)
if (src_stat.file?)
stat.call('downloading', src_item, dst_item) if (stat)
client.fs.file.download(dst_item, src_item)
stat.call('downloaded', src_item, dst_item) if (stat)
elsif (src_stat.directory?)
if (recursive == false)
next
@ -157,14 +159,16 @@ class Dir < Rex::Post::Dir
rescue
end
download(dst_item, src_item, recursive)
stat.call('mirroring', src_item, dst_item) if (stat)
download(dst_item, src_item, recursive, &stat)
stat.call('mirrored', src_item, dst_item) if (stat)
end
}
end
# Uploads the contents of a local directory to a remote
# directory, optionally in a recursive fashion.
def Dir.upload(dst, src, recursive = false)
def Dir.upload(dst, src, recursive = false, &stat)
::Dir.entries(src).each { |src_sub|
dst_item = dst + File::SEPARATOR + src_sub
src_item = src + ::File::SEPARATOR + src_sub
@ -176,7 +180,9 @@ class Dir < Rex::Post::Dir
src_stat = ::File.stat(src_item)
if (src_stat.file?)
stat.call('uploading', src_item, dst_item) if (stat)
client.fs.file.upload(dst_item, src_item)
stat.call('uploaded', src_item, dst_item) if (stat)
elsif (src_stat.directory?)
if (recursive == false)
next
@ -187,7 +193,9 @@ class Dir < Rex::Post::Dir
rescue
end
upload(dst_item, src_item, recursive)
stat.call('mirroring', src_item, dst_item) if (stat)
upload(dst_item, src_item, recursive, &stat)
stat.call('mirrored', src_item, dst_item) if (stat)
end
}
end

View File

@ -52,10 +52,11 @@ Separator = "\\"
# Upload one or more files to the remote computer the remote
# directory supplied in destination
def File.upload(destination, *src_files)
def File.upload(destination, *src_files, &stat)
src_files.each { |src|
dest = destination
stat.call('uploading', src, dest) if (stat)
if (File.basename(destination) != ::File.basename(src))
dest += File::SEPARATOR + ::File.basename(src)
end
@ -67,15 +68,18 @@ Separator = "\\"
dest_fd.write(src_buf)
dest_fd.close
stat.call('uploaded', src, dest) if (stat)
}
end
# Download one or more files from the remote computer to the local
# directory supplied in destination
def File.download(destination, *src_files)
def File.download(destination, *src_files, &stat)
src_files.each { |src|
dest = destination
stat.call('downloading', src, dest) if (stat)
if (::File.basename(destination) != File.basename(src))
dest += ::File::SEPARATOR + File.basename(src)
end
@ -93,6 +97,8 @@ Separator = "\\"
src_fd.close
dst_fd.close
stat.call('downloaded', src, dest) if (stat)
}
end

View File

@ -20,13 +20,13 @@ class Console
# Dispatchers
require 'rex/post/meterpreter/ui/console/command_dispatcher'
require 'rex/post/meterpreter/ui/console/core'
require 'rex/post/meterpreter/ui/console/command_dispatcher/core'
#
# Initialize the meterpreter console
#
def initialize(client)
super("%bmeterpreter%c")
super("%umeterpreter%c")
# The meterpreter client context
self.client = client
@ -34,7 +34,7 @@ class Console
# Point the input/output handles elsewhere
reset_ui
enstack_dispatcher(Console::Core)
enstack_dispatcher(Console::CommandDispatcher::Core)
end
#

View File

@ -1,4 +1,4 @@
require 'rex/parser/arguments'
require 'rex/post/meterpreter'
module Rex
module Post
@ -13,10 +13,16 @@ module Ui
# Core meterpreter client commands.
#
###
class Console::Core
class Console::CommandDispatcher::Core
include Console::CommandDispatcher
def initialize(shell)
super
self.extensions = []
end
@@use_opts = Rex::Parser::Arguments.new(
"-m" => [ true, "The name of the module or modules to load (Ex: stdapi)." ],
"-h" => [ false, "Help banner." ])
@ -26,12 +32,21 @@ class Console::Core
#
def commands
{
"?" => "Help menu",
"exit" => "Terminate the meterpreter session",
"help" => "Help menu",
"use" => "Load a one or more meterpreter extensions",
"quit" => "Terminate the meterpreter session",
}
end
#
# Core baby.
#
def name
"Core"
end
#
# Terminates the meterpreter session
#
@ -41,6 +56,12 @@ class Console::Core
alias cmd_quit cmd_exit
#
# Displays the help menu
#
def cmd_help(*args)
end
#
# Loads one or more meterpreter extensions
#
@ -66,10 +87,20 @@ class Console::Core
# Load each of the modules
modules.each { |m|
md = m.downcase
if (extensions.include?(md))
print_error("The '#{m}' extension has already been loaded.")
next
end
print("Loading extension #{m}...")
begin
client.core.use(m)
# Use the remote side, then load the client-side
if (client.core.use(md) == true)
add_extension_client(md)
end
rescue
log_error("failure: #{$!}")
next
@ -81,6 +112,39 @@ class Console::Core
return true
end
protected
attr_accessor :extensions
CommDispatcher = Console::CommandDispatcher
#
# Loads the client extension specified in mod
#
def add_extension_client(mod)
clirb = File.join(Rex::Root, "post/meterpreter/ui/console/command_dispatcher/#{mod}.rb")
old = CommDispatcher.constants
require(clirb)
new = CommDispatcher.constants
diff = new - old
if (diff.empty? == true)
print_error("Failed to load client portion of #{mod}.")
return false
end
# Create the dispatcher
klass = CommDispatcher.const_get(diff[0])
# Enstack the dispatcher
self.shell.enstack_dispatcher(klass)
# Insert the module into the list of extensions
self.extensions << mod
end
end
end

View File

@ -0,0 +1,50 @@
require 'rex/post/meterpreter'
module Rex
module Post
module Meterpreter
module Ui
###
#
# Stdapi
# ------
#
# Standard API extension.
#
###
class Console::CommandDispatcher::Stdapi
Klass = Console::CommandDispatcher::Stdapi
include Console::CommandDispatcher
require 'rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs'
def initialize(shell)
super
shell.enstack_dispatcher(Klass::Fs)
end
#
# List of supported commands
#
def commands
{
}
end
#
# Name for this dispatcher
#
def name
"Standard extension"
end
end
end
end
end
end

View File

@ -0,0 +1,206 @@
require 'rex/post/meterpreter'
module Rex
module Post
module Meterpreter
module Ui
###
#
# Stdapi
# ------
#
# Standard API extension.
#
###
class Console::CommandDispatcher::Stdapi::Fs
Klass = Console::CommandDispatcher::Stdapi::Fs
include Console::CommandDispatcher
#
# Options for the download command
#
@@download_opts = Rex::Parser::Arguments.new(
"-r" => [ false, "Download recursively." ])
#
# List of supported commands
#
def commands
{
"cd" => "Change directory",
"download" => "Download a file or directory",
"getwd" => "Print working directory",
"ls" => "List files",
"mkdir" => "Make directory",
"pwd" => "Print working directory",
"rmdir" => "Remove directory",
"upload" => "Upload a file or directory",
}
end
#
# Name for this dispatcher
#
def name
"Stdapi: File system"
end
#
# Change the working directory
#
def cmd_cd(*args)
if (args.length == 0)
print_line("Usage: cd directory")
return true
end
client.fs.dir.chdir(args[0])
return true
end
#
# Downloads a file or directory from the remote machine to the local
# machine.
#
def cmd_download(*args)
if (args.length == 0)
print(
"Usage: download [options] src1 src2 src3 ... destination\n\n" +
"Downloads remote files and directories to the local machine.\n" +
@@download_opts.usage)
return true
end
recursive = false
src_items = []
last = nil
dest = nil
@@download_opts.parse(args) { |opt, idx, val|
case opt
when "-r"
recursive = true
when nil
if (last)
src_items << last
end
last = val
end
}
dest = last
# If there is no destination, assume it's the same as the source.
if (!dest)
dest = src_items[0]
end
# Go through each source item and download them
src_items.each { |src|
stat = client.fs.file.stat(src)
if (stat.directory?)
client.fs.dir.download(dest, src, recursive) { |step, src, dst|
print_status("#{step.ljust(11)}: #{src} -> #{dst}")
}
elsif (stat.file?)
client.fs.file.download(dest, src) { |step, src, dst|
print_status("#{step.ljust(11)}: #{src} -> #{dst}")
}
end
}
return true
end
#
# Lists files
#
# TODO: make this more useful
#
def cmd_ls(*args)
path = args[0] || client.fs.dir.getwd
tbl = Rex::Ui::Text::Table.new(
'Header' => "Listing: #{path}",
'Columns' =>
[
'Name',
'Type',
'Size',
])
items = 0
# Enumerate each item...
client.fs.dir.entries(path).sort.each { |p|
s = client.fs.file.stat(p)
tbl << [ p, s.ftype, s.size ]
items += 1
}
if (items > 0)
print(tbl.to_s)
else
print_line("No entries exist in #{path}")
end
return true
end
#
# Make one or more directory
#
def cmd_mkdir(*args)
if (args.length == 0)
print_line("Usage: mkdir dir1 dir2 dir3 ...")
return true
end
args.each { |dir|
print_line("Creating directory: #{dir}")
client.fs.dir.mkdir(dir)
}
return true
end
#
# Display the working directory
#
def cmd_pwd(*args)
print_line(client.fs.dir.getwd)
end
alias cmd_getwd cmd_pwd
#
# Removes one or more directory if it's empty
#
def cmd_rmdir(*args)
if (args.length == 0)
print_line("Usage: rmdir dir1 dir2 dir3 ...")
return true
end
args.each { |dir|
print_line("Removing directory: #{dir}")
client.fs.dir.rmdir(dir)
}
return true
end
end
end
end
end
end

View File

@ -115,12 +115,15 @@ module DispatcherShell
dispatcher_stack.each { |dispatcher|
begin
if (dispatcher.respond_to?('cmd_' + method))
found = true
eval("
dispatcher.#{'cmd_' + method}(*arguments)
found = true")
")
end
rescue
output.print_error("Error while running command #{method}: #{$!}")
output.print_error(
"Error while running command #{method}: #{$!}" +
"\n\nCall stack:\n#{$@.join("\n")}")
end
# If the dispatcher stack changed as a result of this command,