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) def import_options(options)
options.each_option { |name, opt| 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) self.store(name, opt.default.to_s)
end end
} }
@ -130,14 +132,26 @@ class ModuleDataStore < DataStore
# if we can't directly find it # if we can't directly find it
# #
def fetch(key) 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 end
# #
# Same as fetch # Same as fetch
# #
def [](key) 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
end end

View File

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

View File

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

View File

@ -47,7 +47,7 @@ module Msf::Payload::Windows
method = datastore[name] method = datastore[name]
method = 'seh' if (!method or @@exit_types.include?(method) == false) 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 return true
end end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
require 'rex/parser/arguments' require 'rex/post/meterpreter'
module Rex module Rex
module Post module Post
@ -13,10 +13,16 @@ module Ui
# Core meterpreter client commands. # Core meterpreter client commands.
# #
### ###
class Console::Core class Console::CommandDispatcher::Core
include Console::CommandDispatcher include Console::CommandDispatcher
def initialize(shell)
super
self.extensions = []
end
@@use_opts = Rex::Parser::Arguments.new( @@use_opts = Rex::Parser::Arguments.new(
"-m" => [ true, "The name of the module or modules to load (Ex: stdapi)." ], "-m" => [ true, "The name of the module or modules to load (Ex: stdapi)." ],
"-h" => [ false, "Help banner." ]) "-h" => [ false, "Help banner." ])
@ -26,12 +32,21 @@ class Console::Core
# #
def commands def commands
{ {
"?" => "Help menu",
"exit" => "Terminate the meterpreter session", "exit" => "Terminate the meterpreter session",
"help" => "Help menu",
"use" => "Load a one or more meterpreter extensions", "use" => "Load a one or more meterpreter extensions",
"quit" => "Terminate the meterpreter session", "quit" => "Terminate the meterpreter session",
} }
end end
#
# Core baby.
#
def name
"Core"
end
# #
# Terminates the meterpreter session # Terminates the meterpreter session
# #
@ -41,6 +56,12 @@ class Console::Core
alias cmd_quit cmd_exit alias cmd_quit cmd_exit
#
# Displays the help menu
#
def cmd_help(*args)
end
# #
# Loads one or more meterpreter extensions # Loads one or more meterpreter extensions
# #
@ -66,10 +87,20 @@ class Console::Core
# Load each of the modules # Load each of the modules
modules.each { |m| 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}...") print("Loading extension #{m}...")
begin 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 rescue
log_error("failure: #{$!}") log_error("failure: #{$!}")
next next
@ -81,6 +112,39 @@ class Console::Core
return true return true
end 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
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| dispatcher_stack.each { |dispatcher|
begin begin
if (dispatcher.respond_to?('cmd_' + method)) if (dispatcher.respond_to?('cmd_' + method))
found = true
eval(" eval("
dispatcher.#{'cmd_' + method}(*arguments) dispatcher.#{'cmd_' + method}(*arguments)
found = true") ")
end end
rescue rescue
output.print_error("Error while running command #{method}: #{$!}") output.print_error(
"Error while running command #{method}: #{$!}" +
"\n\nCall stack:\n#{$@.join("\n")}")
end end
# If the dispatcher stack changed as a result of this command, # If the dispatcher stack changed as a result of this command,