Commit e9a8899a authored by Sophie Brun's avatar Sophie Brun

Merge tag 'upstream/1.6.1' into kali/master

Upstream version 1.6.1
parents f241fef6 73a6b1b1
......@@ -5,15 +5,15 @@
Gem::Specification.new do |s|
s.name = "bettercap"
s.version = "1.6.0"
s.version = "1.6.1"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Simone Margaritelli"]
s.date = "2016-12-28"
s.date = "2017-06-29"
s.description = "BetterCap is the state of the art, modular, portable and easily extensible MITM framework featuring ARP, DNS and ICMP spoofing, sslstripping, credentials harvesting and more."
s.email = "evilsocket@gmail.com"
s.executables = ["bettercap"]
s.files = ["LICENSE.md", "README.md", "bin/bettercap", "lib/bettercap.rb", "lib/bettercap/banner", "lib/bettercap/context.rb", "lib/bettercap/discovery/agents/arp.rb", "lib/bettercap/discovery/agents/base.rb", "lib/bettercap/discovery/agents/icmp.rb", "lib/bettercap/discovery/agents/udp.rb", "lib/bettercap/discovery/thread.rb", "lib/bettercap/error.rb", "lib/bettercap/firewalls/base.rb", "lib/bettercap/firewalls/bsd.rb", "lib/bettercap/firewalls/linux.rb", "lib/bettercap/firewalls/redirection.rb", "lib/bettercap/loader.rb", "lib/bettercap/logger.rb", "lib/bettercap/monkey/celluloid/actor.rb", "lib/bettercap/monkey/celluloid/io/udp_socket.rb", "lib/bettercap/monkey/em-proxy/proxy.rb", "lib/bettercap/monkey/openssl/server.rb", "lib/bettercap/monkey/packetfu/pcap.rb", "lib/bettercap/monkey/packetfu/utils.rb", "lib/bettercap/monkey/system.rb", "lib/bettercap/network/arp_reader.rb", "lib/bettercap/network/hw-prefixes", "lib/bettercap/network/network.rb", "lib/bettercap/network/packet_queue.rb", "lib/bettercap/network/protos/base.rb", "lib/bettercap/network/protos/dhcp.rb", "lib/bettercap/network/protos/mysql.rb", "lib/bettercap/network/protos/ntlm.rb", "lib/bettercap/network/protos/snmp.rb", "lib/bettercap/network/protos/teamviewer.rb", "lib/bettercap/network/servers/dnsd.rb", "lib/bettercap/network/servers/httpd.rb", "lib/bettercap/network/services", "lib/bettercap/network/target.rb", "lib/bettercap/network/validator.rb", "lib/bettercap/options/core_options.rb", "lib/bettercap/options/options.rb", "lib/bettercap/options/proxy_options.rb", "lib/bettercap/options/server_options.rb", "lib/bettercap/options/sniff_options.rb", "lib/bettercap/options/spoof_options.rb", "lib/bettercap/pluggable.rb", "lib/bettercap/proxy/http/module.rb", "lib/bettercap/proxy/http/modules/injectcss.rb", "lib/bettercap/proxy/http/modules/injecthtml.rb", "lib/bettercap/proxy/http/modules/injectjs.rb", "lib/bettercap/proxy/http/modules/redirect.rb", "lib/bettercap/proxy/http/proxy.rb", "lib/bettercap/proxy/http/request.rb", "lib/bettercap/proxy/http/response.rb", "lib/bettercap/proxy/http/ssl/authority.rb", "lib/bettercap/proxy/http/ssl/bettercap-ca.pem", "lib/bettercap/proxy/http/ssl/server.rb", "lib/bettercap/proxy/http/sslstrip/cookiemonitor.rb", "lib/bettercap/proxy/http/sslstrip/lock.ico", "lib/bettercap/proxy/http/sslstrip/strip.rb", "lib/bettercap/proxy/http/streamer.rb", "lib/bettercap/proxy/stream_logger.rb", "lib/bettercap/proxy/tcp/module.rb", "lib/bettercap/proxy/tcp/proxy.rb", "lib/bettercap/proxy/thread_pool.rb", "lib/bettercap/shell.rb", "lib/bettercap/sniffer/parsers/base.rb", "lib/bettercap/sniffer/parsers/cookie.rb", "lib/bettercap/sniffer/parsers/custom.rb", "lib/bettercap/sniffer/parsers/dhcp.rb", "lib/bettercap/sniffer/parsers/dict.rb", "lib/bettercap/sniffer/parsers/ftp.rb", "lib/bettercap/sniffer/parsers/httpauth.rb", "lib/bettercap/sniffer/parsers/https.rb", "lib/bettercap/sniffer/parsers/irc.rb", "lib/bettercap/sniffer/parsers/mail.rb", "lib/bettercap/sniffer/parsers/mpd.rb", "lib/bettercap/sniffer/parsers/mysql.rb", "lib/bettercap/sniffer/parsers/nntp.rb", "lib/bettercap/sniffer/parsers/ntlmss.rb", "lib/bettercap/sniffer/parsers/pgsql.rb", "lib/bettercap/sniffer/parsers/post.rb", "lib/bettercap/sniffer/parsers/redis.rb", "lib/bettercap/sniffer/parsers/rlogin.rb", "lib/bettercap/sniffer/parsers/snmp.rb", "lib/bettercap/sniffer/parsers/snpp.rb", "lib/bettercap/sniffer/parsers/teamviewer.rb", "lib/bettercap/sniffer/parsers/url.rb", "lib/bettercap/sniffer/parsers/whatsapp.rb", "lib/bettercap/sniffer/sniffer.rb", "lib/bettercap/spoofers/arp.rb", "lib/bettercap/spoofers/base.rb", "lib/bettercap/spoofers/icmp.rb", "lib/bettercap/spoofers/none.rb", "lib/bettercap/update_checker.rb", "lib/bettercap/version.rb"]
s.files = ["LICENSE.md", "README.md", "bin/bettercap", "lib/bettercap.rb", "lib/bettercap/banner", "lib/bettercap/context.rb", "lib/bettercap/discovery/agents/arp.rb", "lib/bettercap/discovery/agents/base.rb", "lib/bettercap/discovery/agents/icmp.rb", "lib/bettercap/discovery/agents/ndp.rb", "lib/bettercap/discovery/agents/udp.rb", "lib/bettercap/discovery/thread.rb", "lib/bettercap/error.rb", "lib/bettercap/firewalls/base.rb", "lib/bettercap/firewalls/bsd.rb", "lib/bettercap/firewalls/linux.rb", "lib/bettercap/firewalls/redirection.rb", "lib/bettercap/loader.rb", "lib/bettercap/logger.rb", "lib/bettercap/monkey/celluloid/actor.rb", "lib/bettercap/monkey/celluloid/io/udp_socket.rb", "lib/bettercap/monkey/em-proxy/proxy.rb", "lib/bettercap/monkey/openssl/server.rb", "lib/bettercap/monkey/packetfu/pcap.rb", "lib/bettercap/monkey/packetfu/utils.rb", "lib/bettercap/monkey/system.rb", "lib/bettercap/network/arp_reader.rb", "lib/bettercap/network/hw-prefixes", "lib/bettercap/network/ndp_reader.rb", "lib/bettercap/network/network.rb", "lib/bettercap/network/packet_queue.rb", "lib/bettercap/network/protos/base.rb", "lib/bettercap/network/protos/dhcp.rb", "lib/bettercap/network/protos/mysql.rb", "lib/bettercap/network/protos/ntlm.rb", "lib/bettercap/network/protos/snmp.rb", "lib/bettercap/network/protos/teamviewer.rb", "lib/bettercap/network/servers/dnsd.rb", "lib/bettercap/network/servers/httpd.rb", "lib/bettercap/network/services", "lib/bettercap/network/target.rb", "lib/bettercap/network/validator.rb", "lib/bettercap/options/core_options.rb", "lib/bettercap/options/options.rb", "lib/bettercap/options/proxy_options.rb", "lib/bettercap/options/server_options.rb", "lib/bettercap/options/sniff_options.rb", "lib/bettercap/options/spoof_options.rb", "lib/bettercap/pluggable.rb", "lib/bettercap/proxy/http/module.rb", "lib/bettercap/proxy/http/modules/injectcss.rb", "lib/bettercap/proxy/http/modules/injecthtml.rb", "lib/bettercap/proxy/http/modules/injectjs.rb", "lib/bettercap/proxy/http/modules/redirect.rb", "lib/bettercap/proxy/http/proxy.rb", "lib/bettercap/proxy/http/request.rb", "lib/bettercap/proxy/http/response.rb", "lib/bettercap/proxy/http/ssl/authority.rb", "lib/bettercap/proxy/http/ssl/bettercap-ca.pem", "lib/bettercap/proxy/http/ssl/server.rb", "lib/bettercap/proxy/http/sslstrip/cookiemonitor.rb", "lib/bettercap/proxy/http/sslstrip/lock.ico", "lib/bettercap/proxy/http/sslstrip/strip.rb", "lib/bettercap/proxy/http/streamer.rb", "lib/bettercap/proxy/stream_logger.rb", "lib/bettercap/proxy/tcp/module.rb", "lib/bettercap/proxy/tcp/proxy.rb", "lib/bettercap/proxy/thread_pool.rb", "lib/bettercap/proxy/udp/module.rb", "lib/bettercap/proxy/udp/pool.rb", "lib/bettercap/proxy/udp/proxy.rb", "lib/bettercap/shell.rb", "lib/bettercap/sniffer/parsers/base.rb", "lib/bettercap/sniffer/parsers/cookie.rb", "lib/bettercap/sniffer/parsers/custom.rb", "lib/bettercap/sniffer/parsers/dhcp.rb", "lib/bettercap/sniffer/parsers/dict.rb", "lib/bettercap/sniffer/parsers/ftp.rb", "lib/bettercap/sniffer/parsers/httpauth.rb", "lib/bettercap/sniffer/parsers/https.rb", "lib/bettercap/sniffer/parsers/irc.rb", "lib/bettercap/sniffer/parsers/mail.rb", "lib/bettercap/sniffer/parsers/mpd.rb", "lib/bettercap/sniffer/parsers/mysql.rb", "lib/bettercap/sniffer/parsers/nntp.rb", "lib/bettercap/sniffer/parsers/ntlmss.rb", "lib/bettercap/sniffer/parsers/pgsql.rb", "lib/bettercap/sniffer/parsers/post.rb", "lib/bettercap/sniffer/parsers/redis.rb", "lib/bettercap/sniffer/parsers/rlogin.rb", "lib/bettercap/sniffer/parsers/snmp.rb", "lib/bettercap/sniffer/parsers/snpp.rb", "lib/bettercap/sniffer/parsers/teamviewer.rb", "lib/bettercap/sniffer/parsers/url.rb", "lib/bettercap/sniffer/parsers/whatsapp.rb", "lib/bettercap/sniffer/sniffer.rb", "lib/bettercap/spoofers/arp.rb", "lib/bettercap/spoofers/base.rb", "lib/bettercap/spoofers/icmp.rb", "lib/bettercap/spoofers/ndp.rb", "lib/bettercap/spoofers/none.rb", "lib/bettercap/update_checker.rb", "lib/bettercap/version.rb"]
s.homepage = "https://github.com/evilsocket/bettercap"
s.licenses = ["GPL-3.0"]
s.rdoc_options = ["--charset=UTF-8"]
......@@ -31,7 +31,7 @@ Gem::Specification.new do |s|
s.add_runtime_dependency(%q<net-dns>, [">= 0.8.0", "~> 0.8"])
s.add_runtime_dependency(%q<network_interface>, [">= 0.0.1", "~> 0.0"])
s.add_runtime_dependency(%q<packetfu>, [">= 1.1.10", "~> 1.1"])
s.add_runtime_dependency(%q<pcaprub>, [">= 0.12.0", "~> 0.12"])
s.add_runtime_dependency(%q<pcaprub>, ["<= 1.1.11", ">= 0.12.0", "~> 0.12"])
s.add_runtime_dependency(%q<rubydns>, [">= 1.0.3", "~> 1.0"])
else
s.add_dependency(%q<colorize>, ["~> 0.8.0"])
......@@ -39,7 +39,7 @@ Gem::Specification.new do |s|
s.add_dependency(%q<net-dns>, [">= 0.8.0", "~> 0.8"])
s.add_dependency(%q<network_interface>, [">= 0.0.1", "~> 0.0"])
s.add_dependency(%q<packetfu>, [">= 1.1.10", "~> 1.1"])
s.add_dependency(%q<pcaprub>, [">= 0.12.0", "~> 0.12"])
s.add_dependency(%q<pcaprub>, ["<= 1.1.11", ">= 0.12.0", "~> 0.12"])
s.add_dependency(%q<rubydns>, [">= 1.0.3", "~> 1.0"])
end
else
......@@ -48,7 +48,7 @@ Gem::Specification.new do |s|
s.add_dependency(%q<net-dns>, [">= 0.8.0", "~> 0.8"])
s.add_dependency(%q<network_interface>, [">= 0.0.1", "~> 0.0"])
s.add_dependency(%q<packetfu>, [">= 1.1.10", "~> 1.1"])
s.add_dependency(%q<pcaprub>, [">= 0.12.0", "~> 0.12"])
s.add_dependency(%q<pcaprub>, ["<= 1.1.11", ">= 0.12.0", "~> 0.12"])
s.add_dependency(%q<rubydns>, [">= 1.0.3", "~> 1.0"])
end
end
......@@ -19,6 +19,8 @@ Encoding.default_internal = Encoding::UTF_8
require 'packetfu'
require 'em-proxy'
require 'eventmachine'
require 'socket'
require 'webrick'
require 'rubydns'
require 'colorize'
......
......@@ -80,12 +80,6 @@ class Context
# Update the Context state parsing network related informations.
def update!
gw = @options.core.gateway || Network.get_gateway
raise BetterCap::Error, "Could not detect the gateway address for interface #{@options.core.iface}, "\
'make sure you\'ve specified the correct network interface to use and to have the '\
'correct network configuration, this could also happen if bettercap '\
'is launched from a virtual environment.' unless Network::Validator.is_ip?(gw)
unless @options.core.use_mac.nil?
cfg = PacketFu::Utils.ifconfig @options.core.iface
raise BetterCap::Error, "Could not determine IPv4 address of '#{@options.core.iface}', make sure this interface "\
......@@ -100,14 +94,34 @@ class Context
cfg = PacketFu::Utils.ifconfig @options.core.iface
raise BetterCap::Error, "Could not determine IPv4 address of '#{@options.core.iface}', make sure this interface "\
'is active and connected.' if cfg[:ip4_obj].nil?
'is active and connected.' if ( cfg[:ip4_obj].nil? and cfg[:ip6_saddr].nil? )
# check if we're on an IPv6 interface
if @options.core.use_ipv6
@iface = Network::Target.new( cfg[:ip6_saddr], cfg[:eth_saddr], cfg[:ip6_obj], cfg[:iface] )
else
@iface = Network::Target.new( cfg[:ip_saddr], cfg[:eth_saddr], cfg[:ip4_obj], cfg[:iface] )
end
@gateway = Network::Target.new gw
@targets = @options.core.targets unless @options.core.targets.nil?
@iface = Network::Target.new( cfg[:ip_saddr], cfg[:eth_saddr], cfg[:ip4_obj], cfg[:iface] )
raise BetterCap::Error, "Could not determine MAC address of '#{@options.core.iface}', make sure this interface "\
'is active and connected.' unless Network::Validator::is_mac?(@iface.mac)
if @options.core.use_ipv6
gw = @options.core.gateway || Network.get_ipv6_gateway
raise BetterCap::Error, "Could not detect the gateway address for interface #{@options.core.iface}, "\
'make sure you\'ve specified the correct network interface to use and to have the '\
'correct network configuration, this could also happen if bettercap '\
'is launched from a virtual environment.' unless Network::Validator.is_ipv6?(gw)
else
gw = @options.core.gateway || Network.get_gateway
raise BetterCap::Error, "Could not detect the gateway address for interface #{@options.core.iface}, "\
'make sure you\'ve specified the correct network interface to use and to have the '\
'correct network configuration, this could also happen if bettercap '\
'is launched from a virtual environment.' unless Network::Validator.is_ip?(gw)
end
@gateway = Network::Target.new gw
Logger.info "[#{@iface.name.green}] #{@iface.to_s(false)}"
Logger.debug '----- NETWORK INFORMATIONS -----'
......@@ -116,9 +130,10 @@ class Context
Logger.debug " local_ip = #{@iface.ip}"
Logger.debug "--------------------------------\n"
@targets = @options.core.targets unless @options.core.targets.nil?
@packets = Network::PacketQueue.new( @iface.name, @options.core.packet_throttle, 4 )
# Spoofers need the context network data to be initialized.
@spoofer = @options.spoof.parse_spoofers
@spoofer = @options.spoof.parse_spoofers(self)
if @options.core.discovery?
tstart = Time.now
......@@ -204,7 +219,7 @@ class Context
Logger.debug 'Disabling port redirections ...'
@redirections.each do |r|
@firewall.del_port_redirection( r )
@firewall.del_port_redirection( r, @options.core.use_ipv6 )
end
Logger.debug 'Restoring firewall state ...'
......@@ -223,7 +238,7 @@ class Context
@redirections = @options.get_redirections(@iface)
@redirections.each do |r|
Logger.debug "Redirecting #{r.protocol} traffic from #{r.src_address.nil? ? '*' : r.src_address}:#{r.src_port} to #{r.dst_address}:#{r.dst_port}"
@firewall.add_port_redirection( r )
@firewall.add_port_redirection( r, @options.core.use_ipv6 )
end
end
......@@ -250,6 +265,11 @@ class Context
@proxies << Proxy::TCP::Proxy.new( @iface.ip, @options.proxies.tcp_proxy_port, @options.proxies.tcp_proxy_upstream_address, @options.proxies.tcp_proxy_upstream_port )
end
# create UP proxy
if @options.proxies.udp_proxy
@proxies << Proxy::UDP::Proxy.new( @iface.ip, @options.proxies.udp_proxy_port, @options.proxies.udp_proxy_upstream_address, @options.proxies.udp_proxy_upstream_port )
end
@proxies.each do |proxy|
proxy.start
end
......
# Parse the NDP table searching for new hosts.
module BetterCap
module Discovery
module Agents
# Class responsible of sending NDP probes to each possible IP on the network.
class Ndp < Discovery::Agents::Base
private
# Send a Neighbor Solicitation packet in order to update neighbor discovery table,
# with target's mac.
# The packet is a broadcast message, so mac is created by "33:33:ff" prefix plus the
# 24 least significant bits of the address.
# Similar rule applies to the destination address. Multicast address is formed from
# the network prefix ff02::1:ff00:0/104 and the 24 least significant bits of the address.
def get_probe( ip )
split_ip = ip.split(':')
dst_mac = "33:33:ff:" + split_ip[-2][-2,2] + ":" + split_ip[-1][0,2] + ":" + split_ip[-1][2,2]
dst_ip = "ff02::1:ff" + split_ip[-2][-2,2] + ":" + split_ip[-1]
p = PacketFu::NDPPacket.new
p.eth_daddr = dst_mac
p.eth_saddr = @ctx.iface.mac
p.eth_proto = 0x86dd
p.ipv6_saddr = @ctx.iface.ip
p.ipv6_daddr = dst_ip
p.ndp_type = 135
p.ndp_taddr = ip.to_s
p.ndp_opt_type = 1
p.ndp_opt_len = 1
p.ndp_lladdr = @ctx.iface.mac
p.ipv6_recalc
p.ndp_recalc
p
end
end
end
end
end
......@@ -119,7 +119,7 @@ class Thread
prev = @ctx.targets
sleep(1) if @ctx.options.core.discovery?
sleep(1)
end
end
end
......
......@@ -81,13 +81,13 @@ class Base
# Apply the +r+ BetterCap::Firewalls::Redirection port redirection object.
# Raise NotImplementedError
def add_port_redirection( r )
def add_port_redirection( r, use_ipv6 )
not_implemented_method!
end
# Remove the +r+ BetterCap::Firewalls::Redirection port redirection object.
# Raise NotImplementedError
def del_port_redirection( r )
def del_port_redirection( r, use_ipv6 )
not_implemented_method!
end
......
......@@ -25,6 +25,12 @@ class BSD < Base
Shell.execute("sysctl -w net.inet.ip.forwarding=#{enabled ? 1 : 0}")
end
# If +enabled+ is true will enable packet forwarding, otherwise it will
# disable it.
def enable_ipv6_forwarding(enabled)
Shell.execute("sysctl -w net.inet6.ip6.forwarding=#{enabled ? 1 : 0}")
end
# If +enabled+ is true will enable packet icmp_echo_ignore_broadcasts, otherwise it will
# disable it.
def enable_icmp_bcast(enabled)
......@@ -36,6 +42,11 @@ class BSD < Base
Shell.execute('sysctl net.inet.ip.forwarding').strip.split(' ')[1] == '1'
end
# Return true if packet forwarding for IPv6 is currently enabled, otherwise false.
def ipv6_forwarding_enabled?
Shell.execute('sysctl net.inet6.ip6.forwarding').strip.split(' ')[1] == '1'
end
# This method is ignored on OSX.
def enable_send_redirects(enabled); end
......@@ -47,7 +58,7 @@ class BSD < Base
end
# Apply the +r+ BetterCap::Firewalls::Redirection port redirection object.
def add_port_redirection( r )
def add_port_redirection( r, use_ipv6 )
# create the pf config file
File.open( @filename, 'a+t' ) do |f|
f.write "#{gen_rule(r)}\n"
......@@ -59,7 +70,7 @@ class BSD < Base
end
# Remove the +r+ BetterCap::Firewalls::Redirection port redirection object.
def del_port_redirection( r )
def del_port_redirection( r, use_ipv6 )
# remove the redirection rule from the existing file
rule = gen_rule(r)
rules = File.readlines(@filename).collect(&:strip).reject(&:empty?)
......
......@@ -20,12 +20,20 @@ class Linux < Base
IP_FORWARD_PATH = IPV4_PATH + "/ip_forward"
ICMP_BCAST_PATH = IPV4_PATH + "/icmp_echo_ignore_broadcasts"
SEND_REDIRECTS_PATH = IPV4_PATH + "/conf/all/send_redirects"
IPV6_PATH = "/proc/sys/net/ipv6"
IPV6_FORWARD_PATH = IPV6_PATH + "/conf/all/forwarding"
def supported?
# Avoids stuff like this https://github.com/evilsocket/bettercap/issues/341
File.file?(IP_FORWARD_PATH)
end
# If +enabled+ is true will enable packet forwarding, otherwise it will
# disable it.
def enable_ipv6_forwarding(enabled)
File.open(IPV6_FORWARD_PATH,'w') { |f| f.puts "#{enabled ? 1 : 0}"}
end
# If +enabled+ is true will enable packet forwarding, otherwise it will
# disable it.
def enable_forwarding(enabled)
......@@ -37,6 +45,12 @@ class Linux < Base
File.open(IP_FORWARD_PATH) { |f| f.read.strip == '1' }
end
# Return true if packet forwarding for IPv6 is currently enabled, otherwise false.
def ipv6_forwarding_enabled?
File.open(IPV6_FORWARD_PATH) { |f| f.read.strip == '1' }
end
# If +enabled+ is true will enable packet icmp_echo_ignore_broadcasts, otherwise it will
# disable it.
def enable_icmp_bcast(enabled)
......@@ -50,21 +64,38 @@ class Linux < Base
end
# Apply the +r+ BetterCap::Firewalls::Redirection port redirection object.
def add_port_redirection( r )
def add_port_redirection( r, use_ipv6 )
table = 'iptables'
cal_dst_address = r.dst_address
if use_ipv6
table = 'ip6tables'
# Prevent sending out ICMPv6 Redirect packets.
Shell.execute("#{table} -I OUTPUT -p icmpv6 --icmpv6-type redirect -j DROP")
# Ipv6 uses a different ip + port representation
cal_dst_address = "[#{r.dst_address}]"
end
# post route
Shell.execute('iptables -t nat -I POSTROUTING -s 0/0 -j MASQUERADE')
Shell.execute("#{table} -t nat -I POSTROUTING -s 0/0 -j MASQUERADE")
# accept all
Shell.execute('iptables -P FORWARD ACCEPT')
Shell.execute("#{table} -P FORWARD ACCEPT")
# add redirection
Shell.execute("iptables -t nat -A PREROUTING -i #{r.interface} -p #{r.protocol} #{r.src_address.nil? ? '' : "-d #{r.src_address}"} --dport #{r.src_port} -j DNAT --to #{r.dst_address}:#{r.dst_port}")
Shell.execute("#{table} -t nat -A PREROUTING -i #{r.interface} -p #{r.protocol} #{r.src_address.nil? ? '' : "-d #{r.src_address}"} --dport #{r.src_port} -j DNAT --to #{cal_dst_address}:#{r.dst_port}")
end
# Remove the +r+ BetterCap::Firewalls::Redirection port redirection object.
def del_port_redirection( r )
def del_port_redirection( r, use_ipv6 )
table = 'iptables'
cal_dst_address = r.dst_address
if use_ipv6
table = 'ip6tables'
# Ipv6 uses a different ip + port representation
cal_dst_address = "[#{r.dst_address}]"
end
# remove post route
Shell.execute('iptables -t nat -D POSTROUTING -s 0/0 -j MASQUERADE')
Shell.execute("#{table} -t nat -D POSTROUTING -s 0/0 -j MASQUERADE")
# remove redirection
Shell.execute("iptables -t nat -D PREROUTING -i #{r.interface} -p #{r.protocol} #{r.src_address.nil? ? '' : "-d #{r.src_address}"} --dport #{r.src_port} -j DNAT --to #{r.dst_address}:#{r.dst_port}")
Shell.execute("#{table} -t nat -D PREROUTING -i #{r.interface} -p #{r.protocol} #{r.src_address.nil? ? '' : "-d #{r.src_address}"} --dport #{r.src_port} -j DNAT --to #{cal_dst_address}:#{r.dst_port}")
end
end
end
......
......@@ -130,7 +130,7 @@ module PacketFu
ret[:ip_src] = [IPAddr.new($1).to_i].pack('N')
ret[:ip4_obj] = IPAddr.new($1)
ret[:ip4_obj] = ret[:ip4_obj].mask($3) if $3
when /inet6 [a-z]+:[\s]*([0-9a-fA-F:\x2f]+)/
when /(fe80[^\/\s]*)/
begin
ret[:ip6_saddr] = $1
ret[:ip6_obj] = IPAddr.new($1)
......@@ -207,4 +207,222 @@ module PacketFu
end
end
class NDPHeader < Struct.new(:ndp_type, :ndp_code, :ndp_sum,
:ndp_reserved, :ndp_tgt, :ndp_opt_type,
:ndp_opt_len, :ndp_lla, :body)
include StructFu
PROTOCOL_NUMBER = 58
def initialize(args={})
super(
Int8.new(args[:ndp_type]),
Int8.new(args[:ndp_code]),
Int16.new(args[:ndp_sum]),
Int32.new(args[:ndp_reserved]),
AddrIpv6.new.read(args[:ndp_tgt] || ("\x00" * 16)),
Int8.new(args[:ndp_opt_type]),
Int8.new(args[:ndp_opt_len]),
EthMac.new.read(args[:ndp_lla])
)
end
# Returns the object in string form.
def to_s
self.to_a.map {|x| x.to_s}.join
end
# Reads a string to populate the object.
def read(str)
force_binary(str)
return self if str.nil?
self[:ndp_type].read(str[0,1])
self[:ndp_code].read(str[1,1])
self[:ndp_sum].read(str[2,2])
self[:ndp_reserved].read(str[4,4])
self[:ndp_tgt].read(str[8,16])
self[:ndp_opt_type].read(str[24,1])
self[:ndp_opt_len].read(str[25,1])
self[:ndp_lla].read(str[26,2])
self
end
# Setter for the type.
def ndp_type=(i); typecast i; end
# Getter for the type.
def ndp_type; self[:ndp_type].to_i; end
# Setter for the code.
def ndp_code=(i); typecast i; end
# Getter for the code.
def ndp_code; self[:ndp_code].to_i; end
# Setter for the checksum. Note, this is calculated automatically with
# ndp_calc_sum.
def ndp_sum=(i); typecast i; end
# Getter for the checksum.
def ndp_sum; self[:ndp_sum].to_i; end
# Setter for the reserved.
def ndp_reserved=(i); typecast i; end
# Getter for the reserved.
def ndp_reserved; self[:ndp_reserved].to_i; end
# Setter for the target address.
def ndp_tgt=(i); typecast i; end
# Getter for the target address.
def ndp_tgt; self[:ndp_tgt].to_i; end
# Setter for the options type field.
def ndp_opt_type=(i); typecast i; end
# Getter for the options type field.
def ndp_opt_type; self[:ndp_opt_type].to_i; end
# Setter for the options length.
def ndp_opt_len=(i); typecast i; end
# Getter for the options length.
def ndp_opt_len; self[:ndp_opt_len].to_i; end
# Setter for the link local address.
def ndp_lla=(i); typecast i; end
# Getter for the link local address.
def ndp_lla; self[:ndp_lla].to_s; end
# Get target address in a more readable form.
def ndp_taddr
self[:ndp_tgt].to_x
end
# Set the target address in a more readable form.
def ndp_taddr=(str)
self[:ndp_tgt].read_x(str)
end
# Sets the link local address in a more readable way.
def ndp_lladdr=(mac)
mac = EthHeader.mac2str(mac)
self[:ndp_lla].read mac
self[:ndp_lla]
end
# Gets the link local address in a more readable way.
def ndp_lladdr
EthHeader.str2mac(self[:ndp_lla].to_s)
end
def ndp_sum_readable
"0x%04x" % ndp_sum
end
# Set flag bits (First three are flag bits, the rest are reserved).
def ndp_set_flags=(bits)
case bits
when "000"
self.ndp_reserved = 0x00000000
when "001"
self.ndp_reserved = 0x20000000
when "010"
self.ndp_reserved = 0x40000000
when "011"
self.ndp_reserved = 0x60000000
when "100"
self.ndp_reserved = 0x80000000
when "101"
self.ndp_reserved = 0xa0000000
when "110"
self.ndp_reserved = 0xc0000000
when "111"
self.ndp_reserved = 0xe0000000
end
end
alias :ndp_tgt_readable :ndp_taddr
alias :ndp_lla_readable :ndp_lladdr
end
module NDPHeaderMixin
def ndp_type=(v); self.ndp_header.ndp_type= v; end
def ndp_type; self.ndp_header.ndp_type; end
def ndp_code=(v); self.ndp_header.ndp_code= v; end
def ndp_code; self.ndp_header.ndp_code; end
def ndp_sum=(v); self.ndp_header.ndp_sum= v; end
def ndp_sum; self.ndp_header.ndp_sum; end
def ndp_sum_readable; self.ndp_header.ndp_sum_readable; end
def ndp_reserved=(v); self.ndp_header.ndp_reserved= v; end
def ndp_reserved; self.ndp_header.ndp_reserved; end
def ndp_tgt=(v); self.ndp_header.ndp_tgt= v; end
def ndp_tgt; self.ndp_header.ndp_tgt; end
def ndp_taddr=(v); self.ndp_header.ndp_taddr= v; end
def ndp_taddr; self.ndp_header.ndp_taddr; end
def ndp_tgt_readable; self.ndp_header.ndp_tgt_readable; end
def ndp_opt_type=(v); self.ndp_header.ndp_opt_type= v; end
def ndp_opt_type; self.ndp_header.ndp_opt_type; end
def ndp_opt_len=(v); self.ndp_header.ndp_opt_len=v; end
def ndp_opt_len;self.ndp_header.ndp_opt_len; end
def ndp_lla=(v); self.ndp_header.ndp_lla=v; end
def ndp_lla;self.ndp_header.ndp_lla; end
def ndp_laddr=(v); self.ndp_header.ndp_laddr= v; end
def ndp_laddr; self.ndp_header.ndp_laddr; end
def ndp_lla_readable; self.ndp_header.ndp_lla_readable; end
def ndp_set_flags=(v); self.ndp_header.ndp_set_flags= v; end
end
class NDPPacket < Packet
include ::PacketFu::EthHeaderMixin
include ::PacketFu::IPv6HeaderMixin
include PacketFu::NDPHeaderMixin
attr_accessor :eth_header, :ipv6_header, :ndp_header
def initialize(args={})
@eth_header = EthHeader.new(args).read(args[:eth])
@ipv6_header = IPv6Header.new(args).read(args[:ipv6])
@ipv6_header.ipv6_next = PacketFu::NDPHeader::PROTOCOL_NUMBER
@ndp_header = NDPHeader.new(args).read(args[:ndp])
@ipv6_header.body = @ndp_header
@eth_header.body = @ipv6_header
@headers = [@eth_header, @ipv6_header, @ndp_header]
super
ndp_calc_sum
end
# Calculates the checksum for the object.
def ndp_calc_sum
checksum = 0
# Compute sum on pseudo-header
[ipv6_src, ipv6_dst].each do |iaddr|
8.times { |i| checksum += (iaddr >> (i*16)) & 0xffff }
end
checksum += PacketFu::NDPHeader::PROTOCOL_NUMBER
checksum += ipv6_len
# Continue with entire ICMPv6 message.
checksum += (ndp_type.to_i << 8) + ndp_code.to_i
checksum += ndp_reserved.to_i >> 16
checksum += ndp_reserved.to_i & 0xffff
8.times { |i| checksum += (ndp_tgt.to_i >> (i*16)) & 0xffff }
checksum += (ndp_opt_type.to_i << 8) + ndp_opt_len.to_i
mac2int = ndp_lla.to_s.unpack('H*').first.to_i(16)
3.times { |i| checksum += (mac2int >> (i*16)) & 0xffff }
checksum = checksum % 0xffff
checksum = 0xffff - checksum
checksum == 0 ? 0xffff : checksum
end
# Recalculates the calculatable fields for NDP.
def ndp_recalc(arg=:all)
arg = arg.intern if arg.respond_to? :intern
case arg
when :ndp_sum
self.ndp_sum = ndp_calc_sum
when :all
self.ndp_sum = ndp_calc_sum
else
raise ArgumentError, "No such field `#{arg}'"
end
end
end
end
module BetterCap
module Network
# This class is responsible for reading the computer ARP table.
class NdpReader
# Parse the Ndp cache searching for the given IP +address+ and return its
# MAC if found, otherwise nil.
def self.find_address( address )
self.parse_cache(address) do |ip,mac|
if ip == address
return mac
end
end
nil
end
private
# Read the computer NDP cache and parse each line, it will yield each
# ip and mac address it will be able to extract.
def self.parse_cache(address)
iface = Context.get.iface.name
Shell.ndp.split("\n").each do |line|
if line.include?(address) && line.include?(iface)
m = line.split
ip = m[0]
hw = Target.normalized_mac( m[4] )
if hw != 'FF:FF:FF:FF:FF:FF'
yield( ip, hw )
end
end
end
end
end
end
end
......@@ -30,6 +30,21 @@ class << self
nil
end
# Return the current network's IPv6 gateway or nil.
def get_ipv6_gateway
route6 = Shell.execute('route -A inet6')
iface = Context.get.options.core.iface
Logger.debug "ROUTE6:\n#{route6}"
route6.split(/\n/).select {|n| n =~ /UG/ }.each do |line|
Network::Validator.each_ipv6_gateway(line) do |address|
return address
end
end
nil
end
# Return a list of IP addresses associated to this device network interfaces.
def get_local_ips
ips = []
......@@ -77,10 +92,19 @@ class << self
# Return the hardware address associated with the specified +ip_address+ using
# the +iface+ network interface.
def get_hw_address( ctx, ip )
hw = ArpReader.find_address( ip )
hw = nil
if ctx.options.core.use_ipv6
hw = NdpReader.find_address( ip )
else
hw = ArpReader.find_address( ip )
end
if hw.nil?
start_agents( ctx, ip )
hw = ArpReader.find_address( ip )
if ctx.options.core.use_ipv6
hw = NdpReader.find_address( ip )
else
hw = ArpReader.find_address( ip )
end
end
hw
end
......@@ -115,8 +139,12 @@ class << self
# complete their job.
# If +address+ is not nil only that ip will be probed.
def start_agents( ctx, address = nil )
[ 'Icmp', 'Udp', 'Arp' ].each do |name|
BetterCap::Loader.load("BetterCap::Discovery::Agents::#{name}").new(ctx, address)
if ctx.options.core.use_ipv6
BetterCap::Loader.load("BetterCap::Discovery::Agents::Ndp").new(ctx, address)
else
[ 'Icmp', 'Udp', 'Arp' ].each do |name|
BetterCap::Loader.load("BetterCap::Discovery::Agents::#{name}").new(ctx, address)
end
end
ctx.packets.wait_empty( ctx.timeout )
end
......
......@@ -47,7 +47,7 @@ class Target
# ip address will be parsed from the computer ARP cache and updated
# accordingly.
def initialize( ip, mac=nil, network=nil, name=nil )
if Network::Validator.is_ip?(ip)
if Network::Validator.is_ip?(ip) or Network::Validator.is_ipv6?(ip)
@ip = ip