From 01139ed655adf07ec9dcc1079d44832b4738278b Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Fri, 2 Jul 2010 17:38:56 +0000 Subject: [PATCH] Adding an autoroute meterpreter script, and enabling route housekeeping to be stored and retrived via Sessions directly, rather than through Rex::Socket::SwitchBoard. git-svn-id: file:///home/svn/framework3/trunk@9663 4d416f70-5f16-0410-b530-b9f4589650da --- lib/msf/core/rpc/session.rb | 3 +- lib/msf/core/session.rb | 5 + lib/rex/socket/switch_board.rb | 15 ++- scripts/meterpreter/autoroute.rb | 166 +++++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 scripts/meterpreter/autoroute.rb diff --git a/lib/msf/core/rpc/session.rb b/lib/msf/core/rpc/session.rb index 4af5577976..f2ecc2a2b1 100644 --- a/lib/msf/core/rpc/session.rb +++ b/lib/msf/core/rpc/session.rb @@ -22,7 +22,8 @@ class Session < Base 'target_host' => s.target_host.to_s, 'username' => s.username.to_s, 'uuid' => s.uuid.to_s, - 'exploit_uuid' => s.exploit_uuid.to_s + 'exploit_uuid' => s.exploit_uuid.to_s, + 'routes' => s.routes.join(",") } end res diff --git a/lib/msf/core/session.rb b/lib/msf/core/session.rb index 83237b7ae1..a4bb2d5e0d 100644 --- a/lib/msf/core/session.rb +++ b/lib/msf/core/session.rb @@ -79,6 +79,7 @@ module Session def initialize self.alive = true self.uuid = Rex::Text.rand_text_alphanumeric(8).downcase + self.routes = [] end # Direct descendents @@ -306,6 +307,10 @@ module Session # The associated username # attr_accessor :username + # + # An array of routes associated with this session + # + attr_accessor :routes protected attr_accessor :via # :nodoc: diff --git a/lib/rex/socket/switch_board.rb b/lib/rex/socket/switch_board.rb index 362baf580a..88978ab8d0 100644 --- a/lib/rex/socket/switch_board.rb +++ b/lib/rex/socket/switch_board.rb @@ -74,7 +74,10 @@ class SwitchBoard # instance. # def self.add_route(subnet, mask, comm) - self.instance.add_route(subnet, mask, comm) + ret = self.instance.add_route(subnet, mask, comm) + if ret && comm.respond_to?(:routes) && comm.routes.kind_of?(Array) + comm.routes << "#{subnet}/#{mask}" + end end # @@ -82,14 +85,20 @@ class SwitchBoard # subnet routing through the supplied Comm instance. # def self.remove_route(subnet, mask, comm) - self.instance.remove_route(subnet, mask, comm) + ret = self.instance.remove_route(subnet, mask, comm) + if ret && comm.respond_to?(:routes) && comm.routes.kind_of?(Array) + comm.routes.delete "#{subnet}/#{mask}" + end end # # Flush all the routes from the switch board routing table. # def self.flush_routes - self.instance.flush_routes + ret = self.instance.flush_routes + if ret && comm.respond_to?(:routes) && comm.routes.kind_of?(Array) + comm.routes.clear + end end # diff --git a/scripts/meterpreter/autoroute.rb b/scripts/meterpreter/autoroute.rb new file mode 100644 index 0000000000..248277f41f --- /dev/null +++ b/scripts/meterpreter/autoroute.rb @@ -0,0 +1,166 @@ +# $Id$ + +# +# Meterpreter script for setting up a route from within a +# Meterpreter session, without having to background the +# current session. + +# Default options +session = client +subnet = nil +netmask = "255.255.255.0" +print_only = false +remove_route = false + +# Options parsing +@@exec_opts = Rex::Parser::Arguments.new( + "-h" => [false, "Help and usage"], + "-s" => [true, "Subnet (IPv4, for example, 10.10.10.0)"], + "-n" => [true, "Netmask (IPv4, for example, 255.255.255.0"], + "-p" => [false, "Print active routing table. All other options are ignored"], + "-d" => [false, "Delete the named route instead of adding it"], +) + +@@exec_opts.parse(args) { |opt, idx, val| + v = val.to_s.strip + case opt + when "-h" + usage + return false + when "-s" + subnet = v + when "-n" + netmask = v + when "-p" + print_only = true + when "-d" + remove_route = true + end +} + +# Identical functionality to command_dispatcher/core.rb, and +# nearly identical code +def print_routes + tbl = Msf::Ui::Console::Table.new( + Msf::Ui::Console::Table::Style::Default, + 'Header' => "Active Routing Table", + 'Prefix' => "\n", + 'Postfix' => "\n", + 'Columns' => + [ + 'Subnet', + 'Netmask', + 'Gateway', + ], + 'ColProps' => + { + 'Subnet' => { 'MaxWidth' => 17 }, + 'Netmask' => { 'MaxWidth' => 17 }, + }) + ret = [] + + Rex::Socket::SwitchBoard.each { |route| + + if (route.comm.kind_of?(Msf::Session)) + gw = "Session #{route.comm.sid}" + else + gw = route.comm.name.split(/::/)[-1] + end + + tbl << [ route.subnet, route.netmask, gw ] + } + if Rex::Socket::SwitchBoard.routes.size > 0 + print tbl.to_s + return Rex::Socket::SwitchBoard.routes + else + print_status "No routes have been added yet" + return false + end +end + +# Yet another IP validator. I'm sure there's some Rex +# function that can just do this. +def check_ip(ip=nil) + return false if(ip.nil? || ip.strip.empty?) + begin + rw = Rex::Socket::RangeWalker.new(ip.strip) + (rw.valid? && rw.length == 1) ? true : false + rescue + false + end +end + +# Adds a route to the framework instance +def add_route(opts={}) + subnet = opts[:subnet] + netmask = opts[:netmask] || "255.255.255.0" # Default class C + Rex::Socket::SwitchBoard.add_route(subnet, netmask, session) +end + +# Removes a route to the framework instance +def delete_route(opts={}) + subnet = opts[:subnet] + netmask = opts[:netmask] || "255.255.255.0" # Default class C + Rex::Socket::SwitchBoard.remove_route(subnet, netmask, session) +end + + +# Defines usage +def usage() + print_status "Usage: run autoroute [-r] -s subnet -n netmask" + print_status "Examples:" + print_status " run autoroute -s 10.1.1.0 -n 255.255.255.0 # Add a route to 10.10.10.1/255.255.255.0" + print_status " run autoroute -s 10.10.10.1 # Netmask defaults to 255.255.255.0" + print_status " run autoroute -p # Print active routing table" + print_status " run autoroute -d -s 10.10.10.1 # Deletes the 10.10.10.1/255.255.255.0 route" + print_status "Use the \"route\" and \"ipconfig\" Meterpreter commands to learn about available routes" +end + +# Validates the command options +def validate_cmd(subnet=nil,netmask=nil) + if subnet.nil? + print_error "Missing -s (subnet) option" + return false + end + + unless(check_ip(subnet)) + print_error "Subnet invalid" + usage + return false + end + + if(netmask and !check_ip(netmask)) + print_error "Netmask invalid" + return usage + end + true +end + +if print_only + return print_routes +end + +return false unless validate_cmd(subnet,netmask) + +if remove_route + print_status("Deleting route to %s/%s..." % [subnet,netmask]) + route_result = delete_route(:subnet => subnet, :netmask => netmask) +else + print_status("Adding a route to %s/%s..." % [subnet,netmask]) + route_result = add_route(:subnet => subnet, :netmask => netmask) +end + +if route_result + print_good "%s route to %s/%s via %s" % [ + (remove_route ? "Deleted" : "Added"), + subnet,netmask,client.sock.peerhost + ] +else + print_error "Could not %s route" % [(remove_route ? "delete" : "add")] +end + +if Rex::Socket::SwitchBoard.routes.size > 0 + print_status "Use the -p option to list all active routes" +end + +return [subnet,netmask,session]