From 5938e79f81786af079ef87a9cfe68558d948a4c2 Mon Sep 17 00:00:00 2001 From: lsanchez-r7 Date: Mon, 8 Jul 2013 16:11:47 -0500 Subject: [PATCH 01/10] Adding the NetworkInterface gem I just moved the c extentions from the metasploit-pcaprub to its own gem --- Gemfile | 1 + Gemfile.lock | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/Gemfile b/Gemfile index fe47bb6b0e..8bfe1ca43f 100755 --- a/Gemfile +++ b/Gemfile @@ -23,6 +23,7 @@ group :db do end group :pcap do + gem 'network_interface', :git => 'https://github.com/lsanchez-r7/network_interface.git' # For sniffer and raw socket modules gem 'pcaprub' end diff --git a/Gemfile.lock b/Gemfile.lock index a72bcdd668..a74d36ed93 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,9 @@ +GIT + remote: https://github.com/lsanchez-r7/network_interface.git + revision: 20953fc3945408d071116d8841ca7ae1aa92272b + specs: + network_interface (0.0.1) + GEM remote: http://rubygems.org/ specs: @@ -68,6 +74,7 @@ DEPENDENCIES json metasploit_data_models (~> 0.16.1) msgpack + network_interface! nokogiri packetfu (= 1.1.8) pcaprub From 50cf8adc1597f6366ff223687774aacde11bae8f Mon Sep 17 00:00:00 2001 From: lsanchez-r7 Date: Mon, 8 Jul 2013 17:22:55 -0500 Subject: [PATCH 02/10] pushing the gem to rubygems --- Gemfile | 2 +- Gemfile.lock | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Gemfile b/Gemfile index 8bfe1ca43f..00977b62ff 100755 --- a/Gemfile +++ b/Gemfile @@ -23,7 +23,7 @@ group :db do end group :pcap do - gem 'network_interface', :git => 'https://github.com/lsanchez-r7/network_interface.git' + gem 'network_interface' # For sniffer and raw socket modules gem 'pcaprub' end diff --git a/Gemfile.lock b/Gemfile.lock index a74d36ed93..dade7f5219 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,9 +1,3 @@ -GIT - remote: https://github.com/lsanchez-r7/network_interface.git - revision: 20953fc3945408d071116d8841ca7ae1aa92272b - specs: - network_interface (0.0.1) - GEM remote: http://rubygems.org/ specs: @@ -37,6 +31,7 @@ GEM metaclass (~> 0.0.1) msgpack (0.5.4) multi_json (1.0.4) + network_interface (0.0.1) nokogiri (1.5.9) packetfu (1.1.8) pcaprub (0.11.3) @@ -74,7 +69,7 @@ DEPENDENCIES json metasploit_data_models (~> 0.16.1) msgpack - network_interface! + network_interface nokogiri packetfu (= 1.1.8) pcaprub From 5c93fb284965b8732d890acf92485ba072a24ded Mon Sep 17 00:00:00 2001 From: lsanchez-r7 Date: Mon, 8 Jul 2013 17:24:28 -0500 Subject: [PATCH 03/10] arp_sweep is once again working modified the capture mixin to use NetworkInteface instead of pcaprub for interfaces and addresses FIXRM #8023,#7943 --- lib/msf/core/exploit/capture.rb | 94 ++++++++++--------- .../auxiliary/scanner/discovery/arp_sweep.rb | 2 +- 2 files changed, 51 insertions(+), 45 deletions(-) diff --git a/lib/msf/core/exploit/capture.rb b/lib/msf/core/exploit/capture.rb index 2c1ee4702a..507780360b 100644 --- a/lib/msf/core/exploit/capture.rb +++ b/lib/msf/core/exploit/capture.rb @@ -53,6 +53,14 @@ module Capture @pcaprub_error = e end + begin + require 'network_interface' + @network_interface_loaded = true + rescue ::Exception => e + @network_interface_loaded = false + @network_interface_error = e + end + end def stats_recv(pcap=self.capture) @@ -376,7 +384,10 @@ module Capture if not @pcaprub_loaded print_status("The Pcaprub module is not available: #{@pcaprub_error}") raise RuntimeError, "Pcaprub not available" - else + elsif not @network_interface_loaded + print_status("The NetworkInterface module is not available: #{@network_interface_error}") + raise RuntimeError, "NetworkInterface not available" + else true end end @@ -406,29 +417,24 @@ module Capture #Netifaces code - # netifaces code is not available in pcaprub 0.9.2 and prior, - # which is going to be installed in a lot of places. Modules - # which want it should check explicitly for it. TODO: Bug upstream - # to release it for real in 0.9.3 def netifaces_implemented? - @pcaprub_loaded and - Pcap.respond_to?(:lookupaddrs) and - Pcap.respond_to?(:interfaces) and - Pcap.respond_to?(:addresses) + @network_interface_loaded and + NetworkInterface.respond_to?(:interfaces) and + NetworkInterface.respond_to?(:addresses) end def list_interfaces check_pcaprub_loaded - Pcap.interfaces + NetworkInterface.interfaces end def is_interface?(dev) check_pcaprub_loaded if RUBY_PLATFORM == "i386-mingw32" if dev =~ /\\Device\\NPF_\{[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}\}/ - return Pcap.interfaces.include?(dev) + return NetworkInterface.interfaces.include?(dev) elsif dev.to_s =~ /^[0-9]{1,2}$/ - if (dev.to_i <= Pcap.interfaces.length) and (dev.to_i >= 0) + if (dev.to_i <= NetworkInterface.interfaces.length) and (dev.to_i >= 0) return true else return false @@ -437,7 +443,7 @@ module Capture return false end else - return Pcap.interfaces.include?(dev) + return NetworkInterface.interfaces.include?(dev) end end @@ -447,7 +453,7 @@ module Capture if RUBY_PLATFORM == "i386-mingw32" if dev.to_s =~ /^[0-9]{1,2}$/ if is_interface?(dev) - Pcap.interfaces[(dev.to_i) - 1] + NetworkInterface.interfaces[(dev.to_i) - 1] else return dev end @@ -462,80 +468,80 @@ module Capture def get_mac(dev) check_pcaprub_loaded dev = get_interface_guid(dev) - addrs = Pcap.addresses(dev) + addrs = NetworkInterface.addresses(dev) raise RuntimeError, "Interface #{dev} does not exist" if !addrs - raise RuntimeError, "Can not get mac address for interface #{dev}" if !addrs[Pcap::AF_LINK][0]['addr'] - addrs[Pcap::AF_LINK][0]['addr'] + raise RuntimeError, "Can not get mac address for interface #{dev}" if !addrs[NetworkInterface::AF_LINK][0]['addr'] + addrs[NetworkInterface::AF_LINK][0]['addr'] end def get_ipv4_addr_count(dev) check_pcaprub_loaded dev = get_interface_guid(dev) - addrs = Pcap.addresses(dev) + addrs = NetworkInterface.addresses(dev) raise RuntimeError, "Interface #{dev} does not exist" if !addrs - addrs[Pcap::AF_INET].length + addrs[NetworkInterface::AF_INET].length end def get_ipv4_addr(dev, num=0) check_pcaprub_loaded dev = get_interface_guid(dev) - addrs = Pcap.addresses(dev) + addrs = NetworkInterface.addresses(dev) raise RuntimeError, "Interface #{dev} do not exists" if !addrs - raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[Pcap::AF_INET].length < num + 1 - raise RuntimeError, "Can not get the IPv4 address for interface #{dev}" if !addrs[Pcap::AF_INET][num]['addr'] - addrs[Pcap::AF_INET][num]['addr'] + raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1 + raise RuntimeError, "Can not get the IPv4 address for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['addr'] + addrs[NetworkInterface::AF_INET][num]['addr'] end def get_ipv4_netmask(dev, num=0) check_pcaprub_loaded dev = get_interface_guid(dev) - addrs = Pcap.addresses(dev) + addrs = NetworkInterface.addresses(dev) raise RuntimeError, "Interface #{dev} do not exists" if !addrs - raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[Pcap::AF_INET].length < num + 1 - raise RuntimeError, "Can not get IPv4 netmask for interface #{dev}" if !addrs[Pcap::AF_INET][num]['netmask'] - addrs[Pcap::AF_INET][num]['netmask'] + raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1 + raise RuntimeError, "Can not get IPv4 netmask for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['netmask'] + addrs[NetworkInterface::AF_INET][num]['netmask'] end def get_ipv4_broadcast(dev, num=0) check_pcaprub_loaded dev = get_interface_guid(dev) - addrs = Pcap.addresses(dev) + addrs = NetworkInterface.addresses(dev) raise RuntimeError, "Interface #{dev} do not exists" if !addrs - raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[Pcap::AF_INET].length < num + 1 - raise RuntimeError, "Can not get IPv4 broadcast address for interface #{dev}" if !addrs[Pcap::AF_INET][num]['broadcast'] - addrs[Pcap::AF_INET][num]['broadcast'] + raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1 + raise RuntimeError, "Can not get IPv4 broadcast address for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['broadcast'] + addrs[NetworkInterface::AF_INET][num]['broadcast'] end def get_ipv6_addr_count(dev) check_pcaprub_loaded dev = get_interface_guid(dev) - raise RuntimeError, "IPv6 information is not available on this platform" if not ::Pcap.const_defined?(:AF_INET6) - addrs = Pcap.addresses(dev) + raise RuntimeError, "IPv6 information is not available on this platform" if not ::NetworkInterface.const_defined?(:AF_INET6) + addrs = NetworkInterface.addresses(dev) raise RuntimeError, "Interface #{dev} do not exists" if !addrs - addrs[Pcap::AF_INET6].length + addrs[NetworkInterface::AF_INET6].length end # NOTE: IPv6 is not implemented on Windows def get_ipv6_addr(dev, num=0) check_pcaprub_loaded dev = get_interface_guid(dev) - raise RuntimeError, "IPv6 information is not available on this platform" if not ::Pcap.const_defined?(:AF_INET6) - addrs = Pcap.addresses(dev) + raise RuntimeError, "IPv6 information is not available on this platform" if not ::NetworkInterface.const_defined?(:AF_INET6) + addrs = NetworkInterface.addresses(dev) raise RuntimeError, "Interface #{dev} do not exists" if !addrs - raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[Pcap::AF_INET6].length < num + 1 - raise RuntimeError, "Can not get ipv6 address for interface #{dev}" if !addrs[Pcap::AF_INET6][num]['addr'] - addrs[Pcap::AF_INET6][num]['addr'].gsub(/%(.)*$/,'') + raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[NetworkInterface::AF_INET6].length < num + 1 + raise RuntimeError, "Can not get ipv6 address for interface #{dev}" if !addrs[NetworkInterface::AF_INET6][num]['addr'] + addrs[NetworkInterface::AF_INET6][num]['addr'].gsub(/%(.)*$/,'') end def get_ipv6_netmask(dev, num=0) check_pcaprub_loaded dev = get_interface_guid(dev) - raise RuntimeError, "IPv6 information is not available on this platform" if not ::Pcap.const_defined?(:AF_INET6) - addrs = Pcap.addresses(dev) + raise RuntimeError, "IPv6 information is not available on this platform" if not ::NetworkInterface.const_defined?(:AF_INET6) + addrs = NetworkInterface.addresses(dev) raise RuntimeError, "Interface #{dev} do not exists" if !addrs - raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[Pcap::AF_INET6].length < num + 1 - raise RuntimeError, "Can not get ipv6 netmask address for interface #{dev}" if !addrs[Pcap::AF_INET6][num]['netmask'] - addrs[Pcap::AF_INET6][num]['netmask'] + raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[NetworkInterface::AF_INET6].length < num + 1 + raise RuntimeError, "Can not get ipv6 netmask address for interface #{dev}" if !addrs[NetworkInterface::AF_INET6][num]['netmask'] + addrs[NetworkInterface::AF_INET6][num]['netmask'] end # Protocol-specific encoding/decoding methods until more diff --git a/modules/auxiliary/scanner/discovery/arp_sweep.rb b/modules/auxiliary/scanner/discovery/arp_sweep.rb index 5b1e584ed4..01b315ce74 100644 --- a/modules/auxiliary/scanner/discovery/arp_sweep.rb +++ b/modules/auxiliary/scanner/discovery/arp_sweep.rb @@ -44,7 +44,7 @@ class Metasploit3 < Msf::Auxiliary @netifaces = true if not netifaces_implemented? - print_error("WARNING : Pcaprub is not uptodate, some functionality will not be available") + print_error("WARNING : NetworkInterface is not up-to-date, some functionality will not be available") @netifaces = false end From 4541a9e49ed9a0d7bba8b5c120155589c4af0bcd Mon Sep 17 00:00:00 2001 From: lsanchez-r7 Date: Mon, 8 Jul 2013 17:44:50 -0500 Subject: [PATCH 04/10] now with passing msftidy --- lib/msf/core/exploit/capture.rb | 1040 +++++++++++++++---------------- tools/list_interfaces.rb | 3 +- 2 files changed, 522 insertions(+), 521 deletions(-) diff --git a/lib/msf/core/exploit/capture.rb b/lib/msf/core/exploit/capture.rb index 507780360b..6b13a63454 100644 --- a/lib/msf/core/exploit/capture.rb +++ b/lib/msf/core/exploit/capture.rb @@ -13,554 +13,554 @@ module Msf # ### -class Exploit -module Capture + class Exploit + module Capture - # - # Initializes an instance of an exploit module that captures traffic - # + # + # Initializes an instance of an exploit module that captures traffic + # - def initialize(info = {}) - super + def initialize(info = {}) + super - register_options( - [ - OptPath.new('PCAPFILE', [false, 'The name of the PCAP capture file to process']), - OptString.new('INTERFACE', [false, 'The name of the interface']), - OptString.new('FILTER', [false, 'The filter string for capturing traffic']), - OptInt.new('SNAPLEN', [true, 'The number of bytes to capture', 65535]), - OptInt.new('TIMEOUT', [true, 'The number of seconds to wait for new data', 500]), - Opt::RHOST + register_options( + [ + OptPath.new('PCAPFILE', [false, 'The name of the PCAP capture file to process']), + OptString.new('INTERFACE', [false, 'The name of the interface']), + OptString.new('FILTER', [false, 'The filter string for capturing traffic']), + OptInt.new('SNAPLEN', [true, 'The number of bytes to capture', 65535]), + OptInt.new('TIMEOUT', [true, 'The number of seconds to wait for new data', 500]), + Opt::RHOST - ], Msf::Exploit::Capture - ) + ], Msf::Exploit::Capture + ) - register_advanced_options( - [ - OptInt.new('UDP_SECRET', [true, 'The 32-bit cookie for UDP probe requests.', 1297303091]), - OptAddress.new('GATEWAY', [false, 'The gateway IP address. This will be used rather than a random remote address for the UDP probe, if set.']), - OptInt.new('NETMASK', [false, 'The local network mask. This is used to decide if an address is in the local network.', 24]), - ], Msf::Exploit::Capture - ) + register_advanced_options( + [ + OptInt.new('UDP_SECRET', [true, 'The 32-bit cookie for UDP probe requests.', 1297303091]), + OptAddress.new('GATEWAY', [false, 'The gateway IP address. This will be used rather than a random remote address for the UDP probe, if set.']), + OptInt.new('NETMASK', [false, 'The local network mask. This is used to decide if an address is in the local network.', 24]), + ], Msf::Exploit::Capture + ) - require 'packetfu' + require 'packetfu' - begin - require 'pcaprub' - @pcaprub_loaded = true - rescue ::Exception => e - @pcaprub_loaded = false - @pcaprub_error = e - end - - begin - require 'network_interface' - @network_interface_loaded = true - rescue ::Exception => e - @network_interface_loaded = false - @network_interface_error = e - end - - end - - def stats_recv(pcap=self.capture) - return(0) if not pcap - pcap.stats['recv'] - end - - def stats_drop(pcap=self.capture) - return(0) if not pcap - pcap.stats['drop'] - end - - def stats_ifdrop(pcap=self.capture) - return(0) if not pcap - pcap.stats['ifdrop'] - end - - # - # Opens a handle to the specified device - # - def open_pcap(opts={}) - check_pcaprub_loaded - if RUBY_PLATFORM == "i386-mingw32" - if opts['INTERFACE'] or datastore['INTERFACE'] - dev = opts['INTERFACE'] || datastore['INTERFACE'] - if is_interface?(dev) - dev = get_interface_guid(dev) + begin + require 'pcaprub' + @pcaprub_loaded = true + rescue ::Exception => e + @pcaprub_loaded = false + @pcaprub_error = e end - end - else - dev = opts['INTERFACE'] || datastore['INTERFACE'] || nil - end - len = (opts['SNAPLEN'] || datastore['SNAPLEN'] || 65535).to_i - tim = (opts['TIMEOUT'] || datastore['TIMEOUT'] || 0).to_i - fil = opts['FILTER'] || datastore['FILTER'] - arp = opts['ARPCAP'] || true - - # Look for a PCAP file - cap = datastore['PCAPFILE'] || '' - - if(not cap.empty?) - if(not File.exists?(cap)) - raise RuntimeError, "The PCAP file #{cap} could not be found" - end - self.capture = ::Pcap.open_offline(cap) - else - dev ||= ::Pcap.lookupdev - - unless RUBY_PLATFORM == "i386-mingw32" - system("ifconfig", dev, "up") - end - - self.capture = ::Pcap.open_live(dev, len, true, tim) - if arp - self.arp_capture = ::Pcap.open_live(dev, 512, true, tim) - preamble = datastore['UDP_SECRET'].to_i - arp_filter = "arp[6:2] = 2 or (udp[8:4] = #{preamble})" - self.arp_capture.setfilter(arp_filter) - end - end - - if (not self.capture) - raise RuntimeError, "Could not start the capture process" - elsif (arp and !self.arp_capture and cap.empty?) - raise RuntimeError, "Could not start the ARP capture process" - end - - self.capture.setfilter(fil) if fil - end - - def close_pcap - return if not self.capture - self.capture = nil - self.arp_capture = nil - GC.start() - end - - def capture_extract_ies(raw) - set = {} - ret = 0 - idx = 0 - len = 0 - - while (idx < raw.length) - len = raw[idx+1] - return set if not len - set[ raw[idx] ] ||= [] - set[ raw[idx] ].push(raw[idx + 2, len]) - idx += len + 2 - end - - return set - end - - # - # This monstrosity works around a series of bugs in the interrupt - # signal handling of Ruby 1.9 - # - def each_packet - return if not capture - begin - @capture_count = 0 - reader = framework.threads.spawn("PcapReceiver", false) do - capture.each do |pkt| - yield(pkt) - @capture_count += 1 + begin + require 'network_interface' + @network_interface_loaded = true + rescue ::Exception => e + @network_interface_loaded = false + @network_interface_error = e end + end - reader.join - rescue ::Exception - raise $! - ensure - reader.kill if reader.alive? - end - @capture_count - end - - # Injects a packet on the wire. For all injection-related functions, it's - # on the module to open up a capture device first (this way, we don't - # needlessly spawn new capture devices). - def inject(pkt="",pcap=self.capture) - check_pcaprub_loaded - if not pcap - raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" - else - pcap.inject(pkt.to_s) # Can be a PacketFu Packet object or a pre-packed string - end - end - - # Injects an Ethernet packet with an optional payload. The payload - # may be a regular PacketFu packet, an EthHeader, or a string. - def inject_eth(args={}) - eth_daddr = args[:eth_daddr] || "ff:ff:ff:ff:ff:ff" - eth_saddr = args[:eth_saddr] || "00:00:00:00:00:00" - eth_type = args[:eth_type] || 0x0800 # IP default - payload = args[:payload] - pcap = args[:pcap] || self.capture - p = PacketFu::EthPacket.new - p.eth_daddr = eth_daddr - p.eth_saddr = eth_saddr - p.eth_proto = eth_type - if payload - if payload.kind_of? PacketFu::EthPacket - p.payload = payload.eth_header.body - elsif payload.kind_of? PacketFu::EthHeader - p.payload = payload.body - else - p.payload = payload.to_s + def stats_recv(pcap=self.capture) + return(0) if not pcap + pcap.stats['recv'] end - end - inject p.to_s,pcap - end - def inject_pcap(pcap_file, filter=nil, delay = 0, pcap=self.capture) - check_pcaprub_loaded - if not pcap - raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" - end + def stats_drop(pcap=self.capture) + return(0) if not pcap + pcap.stats['drop'] + end - if(not File.exists?(pcap_file)) - raise RuntimeError, "The PCAP file #{pcap_file} could not be found" - end + def stats_ifdrop(pcap=self.capture) + return(0) if not pcap + pcap.stats['ifdrop'] + end - if(pcap_file.empty?) - raise RuntimeError, "The PCAP file #{pcap_file} is empty" - end - - capture_file = ::Pcap.open_offline(pcap_file) - capture_file.setfilter(filter) if filter - while (pkt = capture_file.next) do - pcap.inject(pkt) - Kernel.select(nil, nil, nil, (delay * 1.0)/1000) - end - GC.start - end - - # Capture_sendto is intended to replace the old Rex::Socket::Ip.sendto method. It requires - # a payload and a destination address. To send to the broadcast address, set bcast - # to true (this will guarantee that packets will be sent even if ARP doesn't work - # out). - def capture_sendto(payload="", dhost=nil, bcast=false, dev=nil) - raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" unless self.capture - raise RuntimeError, "Must specify a host to sendto" unless dhost - dev ||= datastore['INTERFACE'] - dst_mac,src_mac = lookup_eth(dhost,dev) - if dst_mac == nil and not bcast - return false - end - inject_eth(:payload => payload, :eth_daddr => dst_mac, :eth_saddr => src_mac) - end - - # The return value either be a PacketFu::Packet object, or nil - def inject_reply(proto=:udp,pcap=self.capture) - reply = nil - to = (datastore['TIMEOUT'] || 500).to_f / 1000.0 - if not pcap - raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" - else - begin - ::Timeout.timeout(to) do - pcap.each do |r| - packet = PacketFu::Packet.parse(r) - next unless packet.proto.map {|x| x.downcase.to_sym}.include? proto - reply = packet - break + # + # Opens a handle to the specified device + # + def open_pcap(opts={}) + check_pcaprub_loaded + if RUBY_PLATFORM == "i386-mingw32" + if opts['INTERFACE'] or datastore['INTERFACE'] + dev = opts['INTERFACE'] || datastore['INTERFACE'] + if is_interface?(dev) + dev = get_interface_guid(dev) + end end - end - rescue ::Timeout::Error - end - end - return reply - end - - # This ascertains the correct Ethernet addresses one should use to - # ensure injected IP packets actually get where they are going, and - # manages the self.arp_cache hash. It always uses self.arp_capture - # do inject and capture packets, and will always first fire off a - # UDP packet using the regular socket to learn the source host's - # and gateway's mac addresses. - def lookup_eth(addr=nil,iface=nil) - raise RuntimeError, "Could not access the capture process." if not self.arp_capture - - self.arp_cache ||= {} - self.dst_cache ||= {} - - return self.dst_cache[addr] if self.dst_cache[addr] - - if !self.arp_cache[Rex::Socket.source_address(addr)] - probe_gateway(addr) - end - - src_mac = self.arp_cache[Rex::Socket.source_address(addr)] - if should_arp?(addr) - dst_mac = self.arp_cache[addr] || arp(addr) - else - dst_mac = self.arp_cache[:gateway] - end - - self.dst_cache[addr] = [dst_mac,src_mac] - end - - def probe_gateway(addr) - dst_host = (datastore['GATEWAY'] || IPAddr.new((rand(16777216) + 2969567232), Socket::AF_INET).to_s) - dst_port = rand(30000)+1024 - preamble = [datastore['UDP_SECRET']].pack("N") - secret = "#{preamble}#{Rex::Text.rand_text(rand(0xff)+1)}" - UDPSocket.open.send(secret,0,dst_host,dst_port) - begin - to = (datastore['TIMEOUT'] || 1500).to_f / 1000.0 - ::Timeout.timeout(to) do - while(my_packet = inject_reply(:udp,self.arp_capture)) - if my_packet.payload == secret - dst_mac = self.arp_cache[:gateway] = my_packet.eth_daddr - src_mac = self.arp_cache[Rex::Socket.source_address(addr)] = my_packet.eth_saddr - return [dst_mac,src_mac] - else - next - end - end - end - rescue ::Timeout::Error - # Well, that didn't work (this common on networks where there's no gatway, like - # VMWare network interfaces. We'll need to use a fake source hardware address. - self.arp_cache[Rex::Socket.source_address(addr)] = "00:00:00:00:00:00" - end - end - - # A pure-Ruby ARP exchange. It uses self.arp_capture to send and recv - # packets, rather than self.capture. - def arp(target_ip=nil) - return self.arp_cache[target_ip] if self.arp_cache[target_ip] - return self.arp_cache[:gateway] unless should_arp? target_ip - source_ip = Rex::Socket.source_address(target_ip) - raise RuntimeError, "Could not access the capture process." if not self.arp_capture - p = arp_packet(target_ip,source_ip) - inject_eth(:eth_type => 0x0806, - :payload => p, - :pcap => self.arp_capture, - :eth_saddr => self.arp_cache[Rex::Socket.source_address(target_ip)] - ) - begin - to = (datastore['TIMEOUT'] || 500).to_f / 1000.0 - ::Timeout.timeout(to) do - while(my_packet = inject_reply(:arp,self.arp_capture)) - if my_packet.arp_saddr_ip == target_ip - self.arp_cache[target_ip] = my_packet.eth_saddr - return self.arp_cache[target_ip] - else - next - end - end - end - rescue ::Timeout::Error - end - end - - # Creates a full ARP packet, mainly for use with inject_eth() - def arp_packet(target_ip=nil,source_ip=nil) - p = PacketFu::ARPPacket.new - p.arp_opcode = 1 - p.arp_daddr_ip = target_ip || datastore['RHOST'] - p.arp_saddr_ip = source_ip || datastore['LHOST'] - my_eth = self.arp_cache[Rex::Socket.source_address(target_ip)] - p.arp_saddr_mac = my_eth || "00:00:00:00:00:00" - return p - end - - # Allow modules to reset their arp caches arbitrarily. - def expire_arpcache - self.arp_cache = {} - end - - # For compatabilty with Msf::Exploit::Remote::Ip - def rhost - datastore['RHOST'] - end - - def check_pcaprub_loaded - if not @pcaprub_loaded - print_status("The Pcaprub module is not available: #{@pcaprub_error}") - raise RuntimeError, "Pcaprub not available" - elsif not @network_interface_loaded - print_status("The NetworkInterface module is not available: #{@network_interface_error}") - raise RuntimeError, "NetworkInterface not available" - else - true - end - end - - def lookupnet - check_pcaprub_loaded - dev = datastore['INTERFACE'] || ::Pcap.lookupdev - mask = datastore['NETMASK'] || 24 - begin - my_net = IPAddr.new("#{Pcap.lookupnet(dev).first}/#{mask}") - rescue RuntimeError => e - @pcaprub_error = e - print_status("Cannot stat device: #{@pcaprub_error}") - raise RuntimeError, "Pcaprub error: #{@pcaprub_error}" - end - return my_net - end - - def should_arp?(ip) - @mydev ||= datastore['INTERFACE'] || ::Pcap.lookupdev - @mymask ||= datastore['NETMASK'] || 24 - @mynet ||= lookupnet - @mynet.include?(IPAddr.new(ip)) - end - - attr_accessor :capture, :arp_cache, :arp_capture, :dst_cache - - #Netifaces code - - def netifaces_implemented? - @network_interface_loaded and - NetworkInterface.respond_to?(:interfaces) and - NetworkInterface.respond_to?(:addresses) - end - - def list_interfaces - check_pcaprub_loaded - NetworkInterface.interfaces - end - - def is_interface?(dev) - check_pcaprub_loaded - if RUBY_PLATFORM == "i386-mingw32" - if dev =~ /\\Device\\NPF_\{[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}\}/ - return NetworkInterface.interfaces.include?(dev) - elsif dev.to_s =~ /^[0-9]{1,2}$/ - if (dev.to_i <= NetworkInterface.interfaces.length) and (dev.to_i >= 0) - return true else + dev = opts['INTERFACE'] || datastore['INTERFACE'] || nil + end + + len = (opts['SNAPLEN'] || datastore['SNAPLEN'] || 65535).to_i + tim = (opts['TIMEOUT'] || datastore['TIMEOUT'] || 0).to_i + fil = opts['FILTER'] || datastore['FILTER'] + arp = opts['ARPCAP'] || true + + # Look for a PCAP file + cap = datastore['PCAPFILE'] || '' + + if (not cap.empty?) + if (not File.exists?(cap)) + raise RuntimeError, "The PCAP file #{cap} could not be found" + end + self.capture = ::Pcap.open_offline(cap) + else + dev ||= ::Pcap.lookupdev + + unless RUBY_PLATFORM == "i386-mingw32" + system("ifconfig", dev, "up") + end + + self.capture = ::Pcap.open_live(dev, len, true, tim) + if arp + self.arp_capture = ::Pcap.open_live(dev, 512, true, tim) + preamble = datastore['UDP_SECRET'].to_i + arp_filter = "arp[6:2] = 2 or (udp[8:4] = #{preamble})" + self.arp_capture.setfilter(arp_filter) + end + end + + if (not self.capture) + raise RuntimeError, "Could not start the capture process" + elsif (arp and !self.arp_capture and cap.empty?) + raise RuntimeError, "Could not start the ARP capture process" + end + + self.capture.setfilter(fil) if fil + end + + def close_pcap + return if not self.capture + self.capture = nil + self.arp_capture = nil + GC.start() + end + + def capture_extract_ies(raw) + set = {} + ret = 0 + idx = 0 + len = 0 + + while (idx < raw.length) + len = raw[idx+1] + return set if not len + set[raw[idx]] ||= [] + set[raw[idx]].push(raw[idx + 2, len]) + idx += len + 2 + end + + return set + end + + # + # This monstrosity works around a series of bugs in the interrupt + # signal handling of Ruby 1.9 + # + def each_packet + return if not capture + begin + @capture_count = 0 + reader = framework.threads.spawn("PcapReceiver", false) do + capture.each do |pkt| + yield(pkt) + @capture_count += 1 + end + end + reader.join + rescue ::Exception + raise $! + ensure + reader.kill if reader.alive? + end + + @capture_count + end + + # Injects a packet on the wire. For all injection-related functions, it's + # on the module to open up a capture device first (this way, we don't + # needlessly spawn new capture devices). + def inject(pkt="", pcap=self.capture) + check_pcaprub_loaded + if not pcap + raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" + else + pcap.inject(pkt.to_s) # Can be a PacketFu Packet object or a pre-packed string + end + end + + # Injects an Ethernet packet with an optional payload. The payload + # may be a regular PacketFu packet, an EthHeader, or a string. + def inject_eth(args={}) + eth_daddr = args[:eth_daddr] || "ff:ff:ff:ff:ff:ff" + eth_saddr = args[:eth_saddr] || "00:00:00:00:00:00" + eth_type = args[:eth_type] || 0x0800 # IP default + payload = args[:payload] + pcap = args[:pcap] || self.capture + p = PacketFu::EthPacket.new + p.eth_daddr = eth_daddr + p.eth_saddr = eth_saddr + p.eth_proto = eth_type + if payload + if payload.kind_of? PacketFu::EthPacket + p.payload = payload.eth_header.body + elsif payload.kind_of? PacketFu::EthHeader + p.payload = payload.body + else + p.payload = payload.to_s + end + end + inject p.to_s, pcap + end + + def inject_pcap(pcap_file, filter=nil, delay = 0, pcap=self.capture) + check_pcaprub_loaded + if not pcap + raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" + end + + if (not File.exists?(pcap_file)) + raise RuntimeError, "The PCAP file #{pcap_file} could not be found" + end + + if (pcap_file.empty?) + raise RuntimeError, "The PCAP file #{pcap_file} is empty" + end + + capture_file = ::Pcap.open_offline(pcap_file) + capture_file.setfilter(filter) if filter + while (pkt = capture_file.next) do + pcap.inject(pkt) + Kernel.select(nil, nil, nil, (delay * 1.0)/1000) + end + GC.start + end + + # Capture_sendto is intended to replace the old Rex::Socket::Ip.sendto method. It requires + # a payload and a destination address. To send to the broadcast address, set bcast + # to true (this will guarantee that packets will be sent even if ARP doesn't work + # out). + def capture_sendto(payload="", dhost=nil, bcast=false, dev=nil) + raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" unless self.capture + raise RuntimeError, "Must specify a host to sendto" unless dhost + dev ||= datastore['INTERFACE'] + dst_mac, src_mac = lookup_eth(dhost, dev) + if dst_mac == nil and not bcast return false end - else - return false + inject_eth(:payload => payload, :eth_daddr => dst_mac, :eth_saddr => src_mac) end - else - return NetworkInterface.interfaces.include?(dev) - end - end - # This function is usefull only on windows where pcaprub use the GUID - def get_interface_guid(dev) - check_pcaprub_loaded - if RUBY_PLATFORM == "i386-mingw32" - if dev.to_s =~ /^[0-9]{1,2}$/ - if is_interface?(dev) - NetworkInterface.interfaces[(dev.to_i) - 1] + # The return value either be a PacketFu::Packet object, or nil + def inject_reply(proto=:udp, pcap=self.capture) + reply = nil + to = (datastore['TIMEOUT'] || 500).to_f / 1000.0 + if not pcap + raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" else + begin + ::Timeout.timeout(to) do + pcap.each do |r| + packet = PacketFu::Packet.parse(r) + next unless packet.proto.map { |x| x.downcase.to_sym }.include? proto + reply = packet + break + end + end + rescue ::Timeout::Error + end + end + return reply + end + + # This ascertains the correct Ethernet addresses one should use to + # ensure injected IP packets actually get where they are going, and + # manages the self.arp_cache hash. It always uses self.arp_capture + # do inject and capture packets, and will always first fire off a + # UDP packet using the regular socket to learn the source host's + # and gateway's mac addresses. + def lookup_eth(addr=nil, iface=nil) + raise RuntimeError, "Could not access the capture process." if not self.arp_capture + + self.arp_cache ||= {} + self.dst_cache ||= {} + + return self.dst_cache[addr] if self.dst_cache[addr] + + if !self.arp_cache[Rex::Socket.source_address(addr)] + probe_gateway(addr) + end + + src_mac = self.arp_cache[Rex::Socket.source_address(addr)] + if should_arp?(addr) + dst_mac = self.arp_cache[addr] || arp(addr) + else + dst_mac = self.arp_cache[:gateway] + end + + self.dst_cache[addr] = [dst_mac, src_mac] + end + + def probe_gateway(addr) + dst_host = (datastore['GATEWAY'] || IPAddr.new((rand(16777216) + 2969567232), Socket::AF_INET).to_s) + dst_port = rand(30000)+1024 + preamble = [datastore['UDP_SECRET']].pack("N") + secret = "#{preamble}#{Rex::Text.rand_text(rand(0xff)+1)}" + UDPSocket.open.send(secret, 0, dst_host, dst_port) + begin + to = (datastore['TIMEOUT'] || 1500).to_f / 1000.0 + ::Timeout.timeout(to) do + while (my_packet = inject_reply(:udp, self.arp_capture)) + if my_packet.payload == secret + dst_mac = self.arp_cache[:gateway] = my_packet.eth_daddr + src_mac = self.arp_cache[Rex::Socket.source_address(addr)] = my_packet.eth_saddr + return [dst_mac, src_mac] + else + next + end + end + end + rescue ::Timeout::Error + # Well, that didn't work (this common on networks where there's no gatway, like + # VMWare network interfaces. We'll need to use a fake source hardware address. + self.arp_cache[Rex::Socket.source_address(addr)] = "00:00:00:00:00:00" + end + end + + # A pure-Ruby ARP exchange. It uses self.arp_capture to send and recv + # packets, rather than self.capture. + def arp(target_ip=nil) + return self.arp_cache[target_ip] if self.arp_cache[target_ip] + return self.arp_cache[:gateway] unless should_arp? target_ip + source_ip = Rex::Socket.source_address(target_ip) + raise RuntimeError, "Could not access the capture process." if not self.arp_capture + p = arp_packet(target_ip, source_ip) + inject_eth(:eth_type => 0x0806, + :payload => p, + :pcap => self.arp_capture, + :eth_saddr => self.arp_cache[Rex::Socket.source_address(target_ip)] + ) + begin + to = (datastore['TIMEOUT'] || 500).to_f / 1000.0 + ::Timeout.timeout(to) do + while (my_packet = inject_reply(:arp, self.arp_capture)) + if my_packet.arp_saddr_ip == target_ip + self.arp_cache[target_ip] = my_packet.eth_saddr + return self.arp_cache[target_ip] + else + next + end + end + end + rescue ::Timeout::Error + end + end + + # Creates a full ARP packet, mainly for use with inject_eth() + def arp_packet(target_ip=nil, source_ip=nil) + p = PacketFu::ARPPacket.new + p.arp_opcode = 1 + p.arp_daddr_ip = target_ip || datastore['RHOST'] + p.arp_saddr_ip = source_ip || datastore['LHOST'] + my_eth = self.arp_cache[Rex::Socket.source_address(target_ip)] + p.arp_saddr_mac = my_eth || "00:00:00:00:00:00" + return p + end + + # Allow modules to reset their arp caches arbitrarily. + def expire_arpcache + self.arp_cache = {} + end + + # For compatabilty with Msf::Exploit::Remote::Ip + def rhost + datastore['RHOST'] + end + + def check_pcaprub_loaded + if not @pcaprub_loaded + print_status("The Pcaprub module is not available: #{@pcaprub_error}") + raise RuntimeError, "Pcaprub not available" + elsif not @network_interface_loaded + print_status("The NetworkInterface module is not available: #{@network_interface_error}") + raise RuntimeError, "NetworkInterface not available" + else + true + end + end + + def lookupnet + check_pcaprub_loaded + dev = datastore['INTERFACE'] || ::Pcap.lookupdev + mask = datastore['NETMASK'] || 24 + begin + my_net = IPAddr.new("#{Pcap.lookupnet(dev).first}/#{mask}") + rescue RuntimeError => e + @pcaprub_error = e + print_status("Cannot stat device: #{@pcaprub_error}") + raise RuntimeError, "Pcaprub error: #{@pcaprub_error}" + end + return my_net + end + + def should_arp?(ip) + @mydev ||= datastore['INTERFACE'] || ::Pcap.lookupdev + @mymask ||= datastore['NETMASK'] || 24 + @mynet ||= lookupnet + @mynet.include?(IPAddr.new(ip)) + end + + attr_accessor :capture, :arp_cache, :arp_capture, :dst_cache + + #Netifaces code + + def netifaces_implemented? + @network_interface_loaded and + NetworkInterface.respond_to?(:interfaces) and + NetworkInterface.respond_to?(:addresses) + end + + def list_interfaces + check_pcaprub_loaded + NetworkInterface.interfaces + end + + def is_interface?(dev) + check_pcaprub_loaded + if RUBY_PLATFORM == "i386-mingw32" + if dev =~ /\\Device\\NPF_\{[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}\}/ + return NetworkInterface.interfaces.include?(dev) + elsif dev.to_s =~ /^[0-9]{1,2}$/ + if (dev.to_i <= NetworkInterface.interfaces.length) and (dev.to_i >= 0) + return true + else + return false + end + else + return false + end + else + return NetworkInterface.interfaces.include?(dev) + end + end + + # This function is usefull only on windows where pcaprub use the GUID + def get_interface_guid(dev) + check_pcaprub_loaded + if RUBY_PLATFORM == "i386-mingw32" + if dev.to_s =~ /^[0-9]{1,2}$/ + if is_interface?(dev) + NetworkInterface.interfaces[(dev.to_i) - 1] + else + return dev + end + else + return dev + end + else #Non windows return dev end - else - return dev end - else #Non windows - return dev + + def get_mac(dev) + check_pcaprub_loaded + dev = get_interface_guid(dev) + addrs = NetworkInterface.addresses(dev) + raise RuntimeError, "Interface #{dev} does not exist" if !addrs + raise RuntimeError, "Can not get mac address for interface #{dev}" if !addrs[NetworkInterface::AF_LINK][0]['addr'] + addrs[NetworkInterface::AF_LINK][0]['addr'] + end + + def get_ipv4_addr_count(dev) + check_pcaprub_loaded + dev = get_interface_guid(dev) + addrs = NetworkInterface.addresses(dev) + raise RuntimeError, "Interface #{dev} does not exist" if !addrs + addrs[NetworkInterface::AF_INET].length + end + + def get_ipv4_addr(dev, num=0) + check_pcaprub_loaded + dev = get_interface_guid(dev) + addrs = NetworkInterface.addresses(dev) + raise RuntimeError, "Interface #{dev} do not exists" if !addrs + raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1 + raise RuntimeError, "Can not get the IPv4 address for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['addr'] + addrs[NetworkInterface::AF_INET][num]['addr'] + end + + def get_ipv4_netmask(dev, num=0) + check_pcaprub_loaded + dev = get_interface_guid(dev) + addrs = NetworkInterface.addresses(dev) + raise RuntimeError, "Interface #{dev} do not exists" if !addrs + raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1 + raise RuntimeError, "Can not get IPv4 netmask for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['netmask'] + addrs[NetworkInterface::AF_INET][num]['netmask'] + end + + def get_ipv4_broadcast(dev, num=0) + check_pcaprub_loaded + dev = get_interface_guid(dev) + addrs = NetworkInterface.addresses(dev) + raise RuntimeError, "Interface #{dev} do not exists" if !addrs + raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1 + raise RuntimeError, "Can not get IPv4 broadcast address for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['broadcast'] + addrs[NetworkInterface::AF_INET][num]['broadcast'] + end + + def get_ipv6_addr_count(dev) + check_pcaprub_loaded + dev = get_interface_guid(dev) + raise RuntimeError, "IPv6 information is not available on this platform" if not ::NetworkInterface.const_defined?(:AF_INET6) + addrs = NetworkInterface.addresses(dev) + raise RuntimeError, "Interface #{dev} do not exists" if !addrs + addrs[NetworkInterface::AF_INET6].length + end + + # NOTE: IPv6 is not implemented on Windows + def get_ipv6_addr(dev, num=0) + check_pcaprub_loaded + dev = get_interface_guid(dev) + raise RuntimeError, "IPv6 information is not available on this platform" if not ::NetworkInterface.const_defined?(:AF_INET6) + addrs = NetworkInterface.addresses(dev) + raise RuntimeError, "Interface #{dev} do not exists" if !addrs + raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[NetworkInterface::AF_INET6].length < num + 1 + raise RuntimeError, "Can not get ipv6 address for interface #{dev}" if !addrs[NetworkInterface::AF_INET6][num]['addr'] + addrs[NetworkInterface::AF_INET6][num]['addr'].gsub(/%(.)*$/, '') + end + + def get_ipv6_netmask(dev, num=0) + check_pcaprub_loaded + dev = get_interface_guid(dev) + raise RuntimeError, "IPv6 information is not available on this platform" if not ::NetworkInterface.const_defined?(:AF_INET6) + addrs = NetworkInterface.addresses(dev) + raise RuntimeError, "Interface #{dev} do not exists" if !addrs + raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[NetworkInterface::AF_INET6].length < num + 1 + raise RuntimeError, "Can not get ipv6 netmask address for interface #{dev}" if !addrs[NetworkInterface::AF_INET6][num]['netmask'] + addrs[NetworkInterface::AF_INET6][num]['netmask'] + end + + # Protocol-specific encoding/decoding methods until more + # application protos get into PacketFu proper + + # Intended to be used as the payload to an ICMP echo request's payload + def capture_icmp_echo_pack(id=nil, seq=nil, payload=nil) + id ||= rand(0x10000) + seq ||= rand(0x10000) + [id, seq, payload.to_s].pack("nna*") + end + + # Decodes and ICMP echo request or response. + def capture_icmp_echo_unpack(data) + data.unpack("nna*") + end + end - end - def get_mac(dev) - check_pcaprub_loaded - dev = get_interface_guid(dev) - addrs = NetworkInterface.addresses(dev) - raise RuntimeError, "Interface #{dev} does not exist" if !addrs - raise RuntimeError, "Can not get mac address for interface #{dev}" if !addrs[NetworkInterface::AF_LINK][0]['addr'] - addrs[NetworkInterface::AF_LINK][0]['addr'] - end - - def get_ipv4_addr_count(dev) - check_pcaprub_loaded - dev = get_interface_guid(dev) - addrs = NetworkInterface.addresses(dev) - raise RuntimeError, "Interface #{dev} does not exist" if !addrs - addrs[NetworkInterface::AF_INET].length - end - - def get_ipv4_addr(dev, num=0) - check_pcaprub_loaded - dev = get_interface_guid(dev) - addrs = NetworkInterface.addresses(dev) - raise RuntimeError, "Interface #{dev} do not exists" if !addrs - raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1 - raise RuntimeError, "Can not get the IPv4 address for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['addr'] - addrs[NetworkInterface::AF_INET][num]['addr'] - end - - def get_ipv4_netmask(dev, num=0) - check_pcaprub_loaded - dev = get_interface_guid(dev) - addrs = NetworkInterface.addresses(dev) - raise RuntimeError, "Interface #{dev} do not exists" if !addrs - raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1 - raise RuntimeError, "Can not get IPv4 netmask for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['netmask'] - addrs[NetworkInterface::AF_INET][num]['netmask'] - end - - def get_ipv4_broadcast(dev, num=0) - check_pcaprub_loaded - dev = get_interface_guid(dev) - addrs = NetworkInterface.addresses(dev) - raise RuntimeError, "Interface #{dev} do not exists" if !addrs - raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1 - raise RuntimeError, "Can not get IPv4 broadcast address for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['broadcast'] - addrs[NetworkInterface::AF_INET][num]['broadcast'] - end - - def get_ipv6_addr_count(dev) - check_pcaprub_loaded - dev = get_interface_guid(dev) - raise RuntimeError, "IPv6 information is not available on this platform" if not ::NetworkInterface.const_defined?(:AF_INET6) - addrs = NetworkInterface.addresses(dev) - raise RuntimeError, "Interface #{dev} do not exists" if !addrs - addrs[NetworkInterface::AF_INET6].length - end - - # NOTE: IPv6 is not implemented on Windows - def get_ipv6_addr(dev, num=0) - check_pcaprub_loaded - dev = get_interface_guid(dev) - raise RuntimeError, "IPv6 information is not available on this platform" if not ::NetworkInterface.const_defined?(:AF_INET6) - addrs = NetworkInterface.addresses(dev) - raise RuntimeError, "Interface #{dev} do not exists" if !addrs - raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[NetworkInterface::AF_INET6].length < num + 1 - raise RuntimeError, "Can not get ipv6 address for interface #{dev}" if !addrs[NetworkInterface::AF_INET6][num]['addr'] - addrs[NetworkInterface::AF_INET6][num]['addr'].gsub(/%(.)*$/,'') - end - - def get_ipv6_netmask(dev, num=0) - check_pcaprub_loaded - dev = get_interface_guid(dev) - raise RuntimeError, "IPv6 information is not available on this platform" if not ::NetworkInterface.const_defined?(:AF_INET6) - addrs = NetworkInterface.addresses(dev) - raise RuntimeError, "Interface #{dev} do not exists" if !addrs - raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[NetworkInterface::AF_INET6].length < num + 1 - raise RuntimeError, "Can not get ipv6 netmask address for interface #{dev}" if !addrs[NetworkInterface::AF_INET6][num]['netmask'] - addrs[NetworkInterface::AF_INET6][num]['netmask'] - end - - # Protocol-specific encoding/decoding methods until more - # application protos get into PacketFu proper - - # Intended to be used as the payload to an ICMP echo request's payload - def capture_icmp_echo_pack(id=nil,seq=nil,payload=nil) - id ||= rand(0x10000) - seq ||= rand(0x10000) - [id,seq,payload.to_s].pack("nna*") - end - - # Decodes and ICMP echo request or response. - def capture_icmp_echo_unpack(data) - data.unpack("nna*") end end - -end - -end diff --git a/tools/list_interfaces.rb b/tools/list_interfaces.rb index a0fac5e833..4fabb6529f 100755 --- a/tools/list_interfaces.rb +++ b/tools/list_interfaces.rb @@ -27,7 +27,8 @@ if RUBY_PLATFORM == "i386-mingw32" rescue ::Exception => e $stderr.puts "Error: pcaprub is not installed..." exit - end + end + unless (Pcap.respond_to?(:lookupaddrs) and Pcap.respond_to?(:interfaces) and Pcap.respond_to?(:addresses)) From 94db2dc83fcd92489a5363e168ff8915314944d8 Mon Sep 17 00:00:00 2001 From: lsanchez-r7 Date: Mon, 8 Jul 2013 17:52:24 -0500 Subject: [PATCH 05/10] updating list_interfaces for windows, this should work? --- tools/list_interfaces.rb | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tools/list_interfaces.rb b/tools/list_interfaces.rb index 4fabb6529f..a4b5032f3d 100755 --- a/tools/list_interfaces.rb +++ b/tools/list_interfaces.rb @@ -29,17 +29,19 @@ if RUBY_PLATFORM == "i386-mingw32" exit end - unless (Pcap.respond_to?(:lookupaddrs) and - Pcap.respond_to?(:interfaces) and - Pcap.respond_to?(:addresses)) - $stderr.puts "Error: Looks like you are not running the latest version of pcaprub" + unless ( + NetworkInterface.respond_to?(:interfaces) and + NetworkInterface.respond_to?(:addresses) and + NetworkInterface.respond_to?(:interface_info) + ) + $stderr.puts "Error: Looks like you are not running the latest version of NetworkInterface" exit end found = false - Pcap.interfaces.each_with_index do |iface, i| + NetworkInterface.interfaces.each_with_index do |iface, i| found = true - detail = Pcap.interface_info(iface) - addr = Pcap.addresses(iface) + detail = NetworkInterface.interface_info(iface) + addr = NetworkInterface.addresses(iface) puts "#" * 70 puts "" puts "INDEX : " + (i + 1).to_s From 250472474ce8ac1ff53890bcb9a55e96598d9411 Mon Sep 17 00:00:00 2001 From: lsanchez-r7 Date: Mon, 8 Jul 2013 17:59:41 -0500 Subject: [PATCH 06/10] updating the list_interfaces.rb to use the gem --- tools/list_interfaces.rb | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tools/list_interfaces.rb b/tools/list_interfaces.rb index a4b5032f3d..0b36cd8a22 100755 --- a/tools/list_interfaces.rb +++ b/tools/list_interfaces.rb @@ -23,11 +23,11 @@ $:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] if RUBY_PLATFORM == "i386-mingw32" begin - require 'pcaprub' + require 'network_interface' rescue ::Exception => e - $stderr.puts "Error: pcaprub is not installed..." + $stderr.puts "Error: NetworkInterface is not installed..." exit - end + end unless ( NetworkInterface.respond_to?(:interfaces) and @@ -48,13 +48,13 @@ if RUBY_PLATFORM == "i386-mingw32" puts "NAME : " + detail["name"] puts "DESCRIPTION : " + detail["description"] puts "GUID : " + detail["guid"] - if addr[Pcap::AF_LINK][0]['addr'] - puts "MAC ADDRESSE : #{addr[Pcap::AF_LINK][0]['addr']}" + if addr[NetworkInterface::AF_LINK][0]['addr'] + puts "MAC ADDRESSE : #{addr[NetworkInterface::AF_LINK][0]['addr']}" else puts "MAC ADDRESSE : NONE" end - if addr[Pcap::AF_INET][0]['addr'] and addr[Pcap::AF_INET][0]['netmask'] - puts "IP ADDRESSE : #{addr[Pcap::AF_INET][0]['addr']}/#{addr[Pcap::AF_INET][0]['netmask']}" + if addr[NetworkInterface::AF_INET][0]['addr'] and addr[NetworkInterface::AF_INET][0]['netmask'] + puts "IP ADDRESSE : #{addr[NetworkInterface::AF_INET][0]['addr']}/#{addr[NetworkInterface::AF_INET][0]['netmask']}" else puts "IP ADDRESSE : NONE" end @@ -69,5 +69,3 @@ else $stderr.puts "Error: This script is usefull only on Windows, under other OS just use the built-in commands (ifconfig, ip link show, ...)" exit end - - From 2bb11693f2f7c4b51d0e053aac63d0762569ec36 Mon Sep 17 00:00:00 2001 From: lsanchez-r7 Date: Mon, 8 Jul 2013 18:16:15 -0500 Subject: [PATCH 07/10] fixing some copy --- tools/list_interfaces.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/list_interfaces.rb b/tools/list_interfaces.rb index 0b36cd8a22..34f53de112 100755 --- a/tools/list_interfaces.rb +++ b/tools/list_interfaces.rb @@ -49,14 +49,14 @@ if RUBY_PLATFORM == "i386-mingw32" puts "DESCRIPTION : " + detail["description"] puts "GUID : " + detail["guid"] if addr[NetworkInterface::AF_LINK][0]['addr'] - puts "MAC ADDRESSE : #{addr[NetworkInterface::AF_LINK][0]['addr']}" + puts "MAC ADDRESS : #{addr[NetworkInterface::AF_LINK][0]['addr']}" else - puts "MAC ADDRESSE : NONE" + puts "MAC ADDRESS : NONE" end if addr[NetworkInterface::AF_INET][0]['addr'] and addr[NetworkInterface::AF_INET][0]['netmask'] - puts "IP ADDRESSE : #{addr[NetworkInterface::AF_INET][0]['addr']}/#{addr[NetworkInterface::AF_INET][0]['netmask']}" + puts "IP ADDRESS : #{addr[NetworkInterface::AF_INET][0]['addr']}/#{addr[NetworkInterface::AF_INET][0]['netmask']}" else - puts "IP ADDRESSE : NONE" + puts "IP ADDRESS : NONE" end puts "" end @@ -66,6 +66,6 @@ if RUBY_PLATFORM == "i386-mingw32" $stderr.puts "Error, no network interfaces have been detected" end else - $stderr.puts "Error: This script is usefull only on Windows, under other OS just use the built-in commands (ifconfig, ip link show, ...)" + $stderr.puts "Error: This script is useful only on Windows, under other OS just use the built-in commands (ifconfig, ip link show, ...)" exit end From 4a3dc2e3659ab84bbf18a6828ddcb473e13169a3 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Tue, 9 Jul 2013 19:56:44 -0500 Subject: [PATCH 08/10] Print all the creds! All your base belong to me. After a short discussion with Tod, we think it's best to print the creds by default. If some dude runs Metasploit in a public place, dumps passwords, and gets shoulder surfed, well, sucks for them :-p --- modules/auxiliary/gather/apache_rave_creds.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/apache_rave_creds.rb b/modules/auxiliary/gather/apache_rave_creds.rb index 425270da3d..5e3fbb3da5 100644 --- a/modules/auxiliary/gather/apache_rave_creds.rb +++ b/modules/auxiliary/gather/apache_rave_creds.rb @@ -184,7 +184,7 @@ class Metasploit3 < Msf::Auxiliary print_status("#{rhost}:#{rport} - Recovering Hashes...") json_info["result"]["resultSet"].each { |result| - vprint_good("#{rhost}:#{rport} - Found cred: #{result["username"]}:#{result["password"]}") + print_good("#{rhost}:#{rport} - Found cred: #{result["username"]}:#{result["password"]}") report_auth_info( :host => rhost, :port => rport, From 71974a8535f4ab1e1a281d8dadb050e3c1328883 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Wed, 10 Jul 2013 11:09:47 -0500 Subject: [PATCH 09/10] to_addr_hex_dump is never used and is too similar to to_hex_dump Not so much value in to_addr_hex_dump, as Meatballs1 suggested, we should remove this. --- lib/rex/text.rb | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/lib/rex/text.rb b/lib/rex/text.rb index 364d38094c..3941e3080b 100644 --- a/lib/rex/text.rb +++ b/lib/rex/text.rb @@ -793,49 +793,6 @@ module Text buf << "\n" end - # - # Converts a string a nicely formatted and addressed ex dump - # - def self.to_addr_hex_dump(str, start_addr=0, width=16) - buf = '' - idx = 0 - cnt = 0 - snl = false - lst = 0 - addr = start_addr - - while (idx < str.length) - - buf << "%08x" % addr - buf << " " * 4 - chunk = str[idx, width] - line = chunk.unpack("H*")[0].scan(/../).join(" ") - buf << line - - if (lst == 0) - lst = line.length - buf << " " * 4 - else - buf << " " * ((lst - line.length) + 4).abs - end - - chunk.unpack("C*").each do |c| - if (c > 0x1f and c < 0x7f) - buf << c.chr - else - buf << "." - end - end - - buf << "\n" - - idx += width - addr += width - end - - buf << "\n" - end - # # Converts a hex string to a raw string # From 56ffa4ae2f9016404d2af19145d11e962bffbcb6 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Wed, 10 Jul 2013 13:25:02 -0500 Subject: [PATCH 10/10] Fixes for network_interface PR #2085 Implementing the suggestions from @limhoff-r7. See #2085 FixRM #8023 FixRM #7943 --- Gemfile | 2 +- Gemfile.lock | 2 +- lib/msf/core/exploit/capture.rb | 26 +++++++++++++------------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Gemfile b/Gemfile index 00977b62ff..0fbbd1a78f 100755 --- a/Gemfile +++ b/Gemfile @@ -23,7 +23,7 @@ group :db do end group :pcap do - gem 'network_interface' + gem 'network_interface', '~> 0.0.1' # For sniffer and raw socket modules gem 'pcaprub' end diff --git a/Gemfile.lock b/Gemfile.lock index dade7f5219..503c913cd9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -69,7 +69,7 @@ DEPENDENCIES json metasploit_data_models (~> 0.16.1) msgpack - network_interface + network_interface (~> 0.0.1) nokogiri packetfu (= 1.1.8) pcaprub diff --git a/lib/msf/core/exploit/capture.rb b/lib/msf/core/exploit/capture.rb index 6b13a63454..043430c819 100644 --- a/lib/msf/core/exploit/capture.rb +++ b/lib/msf/core/exploit/capture.rb @@ -64,17 +64,17 @@ module Msf end def stats_recv(pcap=self.capture) - return(0) if not pcap + return(0) unless pcap pcap.stats['recv'] end def stats_drop(pcap=self.capture) - return(0) if not pcap + return(0) unless pcap pcap.stats['drop'] end def stats_ifdrop(pcap=self.capture) - return(0) if not pcap + return(0) unless pcap pcap.stats['ifdrop'] end @@ -133,7 +133,7 @@ module Msf end def close_pcap - return if not self.capture + return unless self.capture self.capture = nil self.arp_capture = nil GC.start() @@ -147,7 +147,7 @@ module Msf while (idx < raw.length) len = raw[idx+1] - return set if not len + return set unless len set[raw[idx]] ||= [] set[raw[idx]].push(raw[idx + 2, len]) idx += len + 2 @@ -161,7 +161,7 @@ module Msf # signal handling of Ruby 1.9 # def each_packet - return if not capture + return unless capture begin @capture_count = 0 reader = framework.threads.spawn("PcapReceiver", false) do @@ -218,7 +218,7 @@ module Msf def inject_pcap(pcap_file, filter=nil, delay = 0, pcap=self.capture) check_pcaprub_loaded - if not pcap + unless pcap raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" end @@ -234,7 +234,7 @@ module Msf capture_file.setfilter(filter) if filter while (pkt = capture_file.next) do pcap.inject(pkt) - Kernel.select(nil, nil, nil, (delay * 1.0)/1000) + Rex.sleep((delay * 1.0)/1000) end GC.start end @@ -283,7 +283,7 @@ module Msf # UDP packet using the regular socket to learn the source host's # and gateway's mac addresses. def lookup_eth(addr=nil, iface=nil) - raise RuntimeError, "Could not access the capture process." if not self.arp_capture + raise RuntimeError, "Could not access the capture process." unless self.arp_capture self.arp_cache ||= {} self.dst_cache ||= {} @@ -336,7 +336,7 @@ module Msf return self.arp_cache[target_ip] if self.arp_cache[target_ip] return self.arp_cache[:gateway] unless should_arp? target_ip source_ip = Rex::Socket.source_address(target_ip) - raise RuntimeError, "Could not access the capture process." if not self.arp_capture + raise RuntimeError, "Could not access the capture process." unless self.arp_capture p = arp_packet(target_ip, source_ip) inject_eth(:eth_type => 0x0806, :payload => p, @@ -515,7 +515,7 @@ module Msf def get_ipv6_addr_count(dev) check_pcaprub_loaded dev = get_interface_guid(dev) - raise RuntimeError, "IPv6 information is not available on this platform" if not ::NetworkInterface.const_defined?(:AF_INET6) + raise RuntimeError, "IPv6 information is not available on this platform" unless ::NetworkInterface.const_defined?(:AF_INET6) addrs = NetworkInterface.addresses(dev) raise RuntimeError, "Interface #{dev} do not exists" if !addrs addrs[NetworkInterface::AF_INET6].length @@ -525,7 +525,7 @@ module Msf def get_ipv6_addr(dev, num=0) check_pcaprub_loaded dev = get_interface_guid(dev) - raise RuntimeError, "IPv6 information is not available on this platform" if not ::NetworkInterface.const_defined?(:AF_INET6) + raise RuntimeError, "IPv6 information is not available on this platform" unless ::NetworkInterface.const_defined?(:AF_INET6) addrs = NetworkInterface.addresses(dev) raise RuntimeError, "Interface #{dev} do not exists" if !addrs raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[NetworkInterface::AF_INET6].length < num + 1 @@ -536,7 +536,7 @@ module Msf def get_ipv6_netmask(dev, num=0) check_pcaprub_loaded dev = get_interface_guid(dev) - raise RuntimeError, "IPv6 information is not available on this platform" if not ::NetworkInterface.const_defined?(:AF_INET6) + raise RuntimeError, "IPv6 information is not available on this platform" unless ::NetworkInterface.const_defined?(:AF_INET6) addrs = NetworkInterface.addresses(dev) raise RuntimeError, "Interface #{dev} do not exists" if !addrs raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[NetworkInterface::AF_INET6].length < num + 1