Refactor lanattacks ruby code, add command dispatcher

The lanattacks module didn't seem to have a command dispatcher, and
hence loading the module would always result in a failure. This
commit fixes this problem.

The commit contains a bit of a refactor of the lanattacks code to be
a little more modular. It also has a shiny new dispatcher which breaks
the DHCP and TFTP functionality up into separate areas.
bug/bundler_fix
OJ 2013-11-04 17:37:42 +10:00
parent c8ceaa25c6
commit ff78082004
7 changed files with 623 additions and 76 deletions

View File

@ -0,0 +1,79 @@
#!/usr/bin/env ruby
# -*- coding: binary -*-
require 'rex/post/meterpreter/extensions/lanattacks/tlv'
module Rex
module Post
module Meterpreter
module Extensions
module Lanattacks
module Dhcp
###
#
# DHCP Server functionality
#
###
class Dhcp
def initialize(client)
@client = client
end
def start
client.send_request(Packet.create_request('lanattacks_start_dhcp'))
true
end
def reset
client.send_request(Packet.create_request('lanattacks_reset_dhcp'))
true
end
def set_option(name, value)
request = Packet.create_request('lanattacks_set_dhcp_option')
request.add_tlv(TLV_TYPE_LANATTACKS_OPTION_NAME, name)
request.add_tlv(TLV_TYPE_LANATTACKS_OPTION, value)
client.send_request(request)
true
end
def load_options(datastore)
# TODO: change this so that all of the options are set in a single
# payload rather than firing off lots of calls separately
datastore.each do |name, value|
if Regexp.new('DHCPIPSTART|DHCPIPEND|NETMASK|ROUTER|DNSSERVER|BROADCAST|'+
'SERVEONCE|PXE|HOSTNAME|HOSTSTART|FILENAME|PXECONF|SRVHOST') =~ name
set_option(name, value)
end
end
end
def stop
client.send_request(Packet.create_request('lanattacks_stop_dhcp'))
true
end
def log
response = client.send_request(Packet.create_request('lanattacks_dhcp_log'))
entries = []
if( response.result == 0 )
log = response.get_tlv_value( TLV_TYPE_LANATTACKS_RAW )
while log.length > 0
mac = log.slice!(0..5)
ip = log.slice!(0..3)
entries << {
:mac => mac,
:ip => ip
}
end
end
entries
end
attr_accessor :client
end
end; end; end; end; end; end

View File

@ -2,6 +2,8 @@
# -*- coding: binary -*- # -*- coding: binary -*-
require 'rex/post/meterpreter/extensions/lanattacks/tlv' require 'rex/post/meterpreter/extensions/lanattacks/tlv'
require 'rex/post/meterpreter/extensions/lanattacks/dhcp/dhcp'
require 'rex/post/meterpreter/extensions/lanattacks/tftp/tftp'
module Rex module Rex
module Post module Post
@ -16,84 +18,27 @@ module Lanattacks
### ###
class Lanattacks < Extension class Lanattacks < Extension
#
# Initializes an instance of the standard API extension.
#
def initialize(client) def initialize(client)
super(client, 'lanattacks') super(client, 'stdapi')
# Alias the following things on the client object so that they
# can be directly referenced
client.register_extension_aliases( client.register_extension_aliases(
[{ [
{
'name' => 'lanattacks', 'name' => 'lanattacks',
'ext' => self 'ext' => ObjectAliases.new(
},]) {
'dhcp' => Rex::Post::Meterpreter::Extensions::Lanattacks::Dhcp::Dhcp.new(client),
'tftp' => Rex::Post::Meterpreter::Extensions::Lanattacks::Tftp::Tftp.new(client)
}),
}
])
end end
def start_dhcp
client.send_request(Packet.create_request('lanattacks_start_dhcp'))
true
end
def reset_dhcp
client.send_request(Packet.create_request('lanattacks_reset_dhcp'))
true
end
def set_dhcp_option(name, value)
request = Packet.create_request('lanattacks_set_dhcp_option')
request.add_tlv(TLV_TYPE_LANATTACKS_OPTION_NAME, name)
request.add_tlv(TLV_TYPE_LANATTACKS_OPTION, value)
client.send_request(request)
true
end
def load_dhcp_options(datastore)
datastore.each do |name, value|
if Regexp.new('DHCPIPSTART|DHCPIPEND|NETMASK|ROUTER|DNSSERVER|BROADCAST|'+
'SERVEONCE|PXE|HOSTNAME|HOSTSTART|FILENAME|PXECONF|SRVHOST') =~ name
set_dhcp_option(name,value)
end
end
end
def stop_dhcp
client.send_request(Packet.create_request('lanattacks_stop_dhcp'))
true
end
def dhcp_log
response = client.send_request(Packet.create_request('lanattacks_dhcp_log'))
entries = []
if( response.result == 0 )
log = response.get_tlv_value( TLV_TYPE_LANATTACKS_RAW )
while log.length > 0
mac = log.slice!(0..5)
ip = log.slice!(0..3)
entries << [ mac, ip ]
end
end
entries
end
def start_tftp
client.send_request(Packet.create_request('lanattacks_start_tftp'))
true
end
def reset_tftp
client.send_request(Packet.create_request('lanattacks_reset_tftp'))
true
end
def add_tftp_file(filename, data)
request = Packet.create_request('lanattacks_add_tftp_file')
request.add_tlv(TLV_TYPE_LANATTACKS_OPTION_NAME, filename)
request.add_tlv(TLV_TYPE_LANATTACKS_RAW, data, false, true) #compress it
client.send_request(request)
true
end
def stop_tftp
client.send_request(Packet.create_request('lanattacks_stop_tftp'))
true
end
end end
end; end; end; end; end end; end; end; end; end

View File

@ -0,0 +1,50 @@
#!/usr/bin/env ruby
# -*- coding: binary -*-
require 'rex/post/meterpreter/extensions/lanattacks/tlv'
module Rex
module Post
module Meterpreter
module Extensions
module Lanattacks
module Tftp
###
#
# TFTP Server functionality
#
###
class Tftp
def initialize(client)
@client = client
end
def start
client.send_request(Packet.create_request('lanattacks_start_tftp'))
true
end
def reset
client.send_request(Packet.create_request('lanattacks_reset_tftp'))
true
end
def add_file(filename, data)
request = Packet.create_request('lanattacks_add_tftp_file')
request.add_tlv(TLV_TYPE_LANATTACKS_OPTION_NAME, filename)
request.add_tlv(TLV_TYPE_LANATTACKS_RAW, data, false, true) #compress it
client.send_request(request)
true
end
def stop
client.send_request(Packet.create_request('lanattacks_stop_tftp'))
true
end
attr_accessor :client
end
end; end; end; end; end; end

View File

@ -5,10 +5,10 @@ module Meterpreter
module Extensions module Extensions
module Lanattacks module Lanattacks
TLV_TYPE_LANATTACKS_OPTION = TLV_META_TYPE_RAW| (TLV_EXTENSIONS + 1) TLV_TYPE_LANATTACKS_OPTION = TLV_META_TYPE_RAW | (TLV_EXTENSIONS + 1)
TLV_TYPE_LANATTACKS_OPTION_NAME = TLV_META_TYPE_STRING| (TLV_EXTENSIONS + 2) TLV_TYPE_LANATTACKS_OPTION_NAME = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 2)
TLV_TYPE_LANATTACKS_UINT = TLV_META_TYPE_UINT| (TLV_EXTENSIONS + 3) TLV_TYPE_LANATTACKS_UINT = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 3)
TLV_TYPE_LANATTACKS_RAW = TLV_META_TYPE_RAW| (TLV_EXTENSIONS + 4) TLV_TYPE_LANATTACKS_RAW = TLV_META_TYPE_RAW | (TLV_EXTENSIONS + 4)
end end
end end

View File

@ -0,0 +1,60 @@
# -*- coding: binary -*-
require 'rex/post/meterpreter'
module Rex
module Post
module Meterpreter
module Ui
###
#
# Standard API extension.
#
###
class Console::CommandDispatcher::Lanattacks
require 'rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/dhcp'
require 'rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/tftp'
Klass = Console::CommandDispatcher::Lanattacks
Dispatchers =
[
Klass::Dhcp,
Klass::Tftp
]
include Console::CommandDispatcher
#
# Initializes an instance of the stdapi command interaction.
#
def initialize(shell)
super
Dispatchers.each { |d|
shell.enstack_dispatcher(d)
}
end
#
# List of supported commands.
#
def commands
{
}
end
#
# Name for this dispatcher
#
def name
"Lanattacks extension"
end
end
end
end
end
end

View File

@ -0,0 +1,254 @@
# -*- coding: binary -*-
require 'rex/post/meterpreter'
module Rex
module Post
module Meterpreter
module Ui
###
#
# The networking portion of the standard API extension.
#
###
class Console::CommandDispatcher::Lanattacks::Dhcp
Klass = Console::CommandDispatcher::Lanattacks::Dhcp
include Console::CommandDispatcher
#
# List of supported commands.
#
def commands
all = {
"dhcp_start" => "Start the DHCP server",
"dhcp_stop" => "Stop the DHCP server",
"dhcp_reset" => "Reset the DHCP server",
"dhcp_set_option" => "Set a DHCP server option",
"dhcp_load_options" => "Load DHCP optionis from a datastore",
"dhcp_log" => "Log DHCP server activity"
}
reqs = {
"dhcp_start" => [ "lanattacks_start_dhcp" ],
"dhcp_stop" => [ "lanattacks_stop_dhcp" ],
"dhcp_reset" => [ "lanattacks_reset_dhcp" ],
"dhcp_set_option" => [ "lanattacks_set_dhcp_option" ],
"dhcp_load_options" => [ "lanattacks_set_dhcp_option" ],
"dhcp_log" => [ "lanattacks_dhcp_log" ]
}
all.delete_if do |cmd, desc|
del = false
reqs[cmd].each do |req|
next if client.commands.include? req
del = true
break
end
del
end
all
end
#
# Name for this dispatcher.
#
def name
"Lanattacks: DHCP"
end
@@dhcp_start_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ])
def print_dhcp_start_usage
print("dhcp_start [-h]\n\n" +
"Starts a DHCP server in the current Meterpreter session.\n" +
@@dhcp_start_opts.usage + "\n")
end
def cmd_dhcp_start(*args)
@@dhcp_start_opts.parse(args) { |opt, idx, val|
case opt
when '-h'
print_dhcp_start_usage
return true
end
}
print_status( "Starting DHCP server ...")
client.lanattacks.dhcp.start
print_good( "DHCP server startd.")
end
@@dhcp_stop_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ])
def print_dhcp_stop_usage
print("dhcp_stop [-h]\n\n" +
"Stops the currently running DHCP server.\n" +
@@dhcp_stop_opts.usage + "\n")
end
def cmd_dhcp_stop(*args)
@@dhcp_stop_opts.parse(args) { |opt, idx, val|
case opt
when '-h'
print_dhcp_stop_usage
return true
end
}
print_status( "Stopping DHCP server ...")
client.lanattacks.dhcp.stop
print_good( "DHCP server stopped.")
end
@@dhcp_reset_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ])
def print_dhcp_reset_usage
print("dhcp_reset [-h]\n\n" +
"Resets the currently running DHCP server.\n" +
@@dhcp_reset_opts.usage + "\n")
end
def cmd_dhcp_reset(*args)
@@dhcp_reset_opts.parse(args) { |opt, idx, val|
case opt
when '-h'
print_dhcp_reset_usage
return true
end
}
print_status( "Resetting DHCP server ...")
client.lanattacks.dhcp.reset
print_good( "DHCP server reset.")
end
@@dhcp_set_option_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ])
@@dhcp_set_option_valid_options = [
"BROADCAST", "DHCPIPEND", "DHCPIPSTART", "DNSSERVER",
"FILENAME", "HOSTNAME", "HOSTSTART", "NETMASK",
"PXE", "PXECONF", "ROUTER", "SERVEONCE", "SRVHOST"
]
def print_dhcp_set_option_usage
print("dhcp_set_option <name> <value> [-h]\n\n" +
"Set a DHCP server option.\n\n" +
"Valid names are:\n" +
@@dhcp_set_option_valid_options.map {|o| " - #{o}\n" }.join('') +
@@dhcp_set_option_opts.usage + "\n")
end
def cmd_dhcp_set_option(*args)
@@dhcp_set_option_opts.parse(args) { |opt, idx, val|
case opt
when '-h'
print_dhcp_set_option_usage
return true
end
}
if args.length < 2
print_dhcp_set_option_usage
return true
end
name = args.shift.upcase
value = args.shift
if not @@dhcp_set_option_valid_options.include? name
print_error( "Invalid option name '#{name}'." )
return true
end
client.lanattacks.dhcp.set_option(name, value)
end
@@dhcp_load_options_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ])
def print_dhcp_load_options_usage
print("dhcp_load_options <datastore> [-h]\n\n" +
"Load settings from a datstore to the active DHCP server.\n\n" +
"The datastore must be a hash of name/value pairs.\n" +
"Valid names are:\n" +
@@dhcp_set_option_valid_options.map {|o| " - #{o}\n" }.join('') +
@@dhcp_set_option_opts.usage + "\n")
end
def cmd_dhcp_load_options(*args)
@@dhcp_set_option_opts.parse(args) { |opt, idx, val|
case opt
when '-h'
print_dhcp_set_option_usage
return true
end
}
if args.length < 1
print_dhcp_load_options_usage
return true
end
datastore = args.shift
if not datastore.is_a?(Hash)
print_dhcp_load_options_usage
return true
end
client.lanattacks.dhcp.load_options(datastore)
end
@@dhcp_log_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ])
def print_dhcp_log_usage
print("dhcp_log [-h]\n\n" +
"Logs the DHCP operations captured by the DHCP server.\n" +
@@dhcp_log_opts.usage + "\n")
end
def cmd_dhcp_log(*args)
@@dhcp_log_opts.parse(args) { |opt, idx, val|
case opt
when '-h'
print_dhcp_log_usage
return true
end
}
log = client.lanattacks.dhcp.log
table = Rex::Ui::Text::Table.new(
'Header' => 'DHCP Server Log',
'Indent' => 0,
'SortIndex' => 0,
'Columns' => [ 'MAC Address', 'IP Address' ]
)
log.each { |l|
table << [ l[:mac], l[:ip] ]
}
print_line()
print_line( table.to_s )
print_line( "Total log entries: #{log.length}" )
print_line()
end
end
end
end
end
end

View File

@ -0,0 +1,159 @@
# -*- coding: binary -*-
require 'rex/post/meterpreter'
module Rex
module Post
module Meterpreter
module Ui
###
#
# The networking portion of the standard API extension.
#
###
class Console::CommandDispatcher::Lanattacks::Tftp
Klass = Console::CommandDispatcher::Lanattacks::Tftp
include Console::CommandDispatcher
#
# List of supported commands.
#
def commands
all = {
"tftp_start" => "Start the TFTP server",
"tftp_stop" => "Stop the TFTP server",
"tftp_reset" => "Reset the TFTP server",
"tftp_add_file" => "Add a file to the TFTP server"
}
reqs = {
"tftp_start" => [ "lanattacks_start_tftp" ],
"tftp_stop" => [ "lanattacks_stop_tftp" ],
"tftp_reset" => [ "lanattacks_reset_tftp" ],
"tftp_add_file" => [ "lanattacks_add_tftp_file" ],
}
all.delete_if do |cmd, desc|
del = false
reqs[cmd].each do |req|
next if client.commands.include? req
del = true
break
end
del
end
all
end
#
# Name for this dispatcher.
#
def name
"Lanattacks: TFTP"
end
@@tftp_start_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ])
def print_tftp_start_usage
print("tftp_start [-h]\n\n" +
"Starts a TFTP server in the current Meterpreter session.\n" +
@@tftp_start_opts.usage + "\n")
end
def cmd_tftp_start(*args)
@@tftp_start_opts.parse(args) { |opt, idx, val|
case opt
when '-h'
print_tftp_start_usage
return true
end
}
print_status( "Starting TFTP server ..." )
client.lanattacks.tftp.start
print_good( "TFTP server startd." )
end
@@tftp_stop_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ])
def print_tftp_stop_usage
print("tftp_stop [-h]\n\n" +
"Stops the currently running TFTP server.\n" +
@@tftp_stop_opts.usage + "\n")
end
def cmd_tftp_stop(*args)
@@tftp_stop_opts.parse(args) { |opt, idx, val|
case opt
when '-h'
print_tftp_stop_usage
return true
end
}
print_status( "Stopping TFTP server ..." )
client.lanattacks.tftp.stop
print_good( "TFTP server stopped." )
end
@@tftp_reset_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ])
def print_tftp_reset_usage
print("tftp_reset [-h]\n\n" +
"Resets the currently running TFTP server.\n" +
@@tftp_reset_opts.usage + "\n")
end
def cmd_tftp_reset(*args)
@@tftp_reset_opts.parse(args) { |opt, idx, val|
case opt
when '-h'
print_tftp_reset_usage
return true
end
}
print_status( "Resetting TFTP server ..." )
client.lanattacks.tftp.reset
print_good( "TFTP server reset." )
end
@@tftp_add_file_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ])
def print_tftp_add_file_usage
print("tftp_add_file <file> [-h]\n\n" +
"Add a file to the currently running TFTP server.\n" +
@@tftp_add_file_opts.usage + "\n")
end
def cmd_tftp_add_file(*args)
@@tftp_add_file_opts.parse(args) { |opt, idx, val|
case opt
when '-h'
print_tftp_add_file_usage
return true
end
}
name = args.shift
print_status( "Adding file #{name} ..." )
client.lanattacks.tftp.add_file(name, ::File.read(name))
print_good( "File added." )
end
end
end
end
end
end