meterp fs wrapper action rockin the house
git-svn-id: file:///home/svn/incoming/trunk@2793 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
45b1e69210
commit
9a420ac750
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
module Rex
|
||||
Root = File.join(File.dirname(__FILE__), 'rex')
|
||||
end
|
||||
|
||||
# Generic classes
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue