bettercap 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/bettercap.rb +2 -0
- data/lib/bettercap/context.rb +33 -13
- data/lib/bettercap/discovery/agents/ndp.rb +43 -0
- data/lib/bettercap/discovery/thread.rb +1 -1
- data/lib/bettercap/firewalls/base.rb +2 -2
- data/lib/bettercap/firewalls/bsd.rb +13 -2
- data/lib/bettercap/firewalls/linux.rb +38 -7
- data/lib/bettercap/monkey/packetfu/utils.rb +219 -1
- data/lib/bettercap/network/ndp_reader.rb +35 -0
- data/lib/bettercap/network/network.rb +32 -4
- data/lib/bettercap/network/target.rb +1 -1
- data/lib/bettercap/network/validator.rb +33 -0
- data/lib/bettercap/options/core_options.rb +26 -3
- data/lib/bettercap/options/options.rb +5 -0
- data/lib/bettercap/options/proxy_options.rb +73 -1
- data/lib/bettercap/options/spoof_options.rb +10 -2
- data/lib/bettercap/proxy/http/proxy.rb +6 -1
- data/lib/bettercap/proxy/http/response.rb +8 -2
- data/lib/bettercap/proxy/http/ssl/bettercap-ca.pem +52 -48
- data/lib/bettercap/proxy/http/sslstrip/strip.rb +3 -9
- data/lib/bettercap/proxy/http/streamer.rb +1 -1
- data/lib/bettercap/proxy/udp/module.rb +85 -0
- data/lib/bettercap/proxy/udp/pool.rb +86 -0
- data/lib/bettercap/proxy/udp/proxy.rb +92 -0
- data/lib/bettercap/shell.rb +8 -2
- data/lib/bettercap/sniffer/parsers/https.rb +13 -4
- data/lib/bettercap/spoofers/ndp.rb +144 -0
- data/lib/bettercap/version.rb +1 -1
- metadata +15 -3
@@ -0,0 +1,35 @@
|
|
1
|
+
module BetterCap
|
2
|
+
module Network
|
3
|
+
# This class is responsible for reading the computer ARP table.
|
4
|
+
class NdpReader
|
5
|
+
# Parse the Ndp cache searching for the given IP +address+ and return its
|
6
|
+
# MAC if found, otherwise nil.
|
7
|
+
def self.find_address( address )
|
8
|
+
self.parse_cache(address) do |ip,mac|
|
9
|
+
if ip == address
|
10
|
+
return mac
|
11
|
+
end
|
12
|
+
end
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Read the computer NDP cache and parse each line, it will yield each
|
19
|
+
# ip and mac address it will be able to extract.
|
20
|
+
def self.parse_cache(address)
|
21
|
+
iface = Context.get.iface.name
|
22
|
+
Shell.ndp.split("\n").each do |line|
|
23
|
+
if line.include?(address) && line.include?(iface)
|
24
|
+
m = line.split
|
25
|
+
ip = m[0]
|
26
|
+
hw = Target.normalized_mac( m[4] )
|
27
|
+
if hw != 'FF:FF:FF:FF:FF:FF'
|
28
|
+
yield( ip, hw )
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -30,6 +30,21 @@ class << self
|
|
30
30
|
nil
|
31
31
|
end
|
32
32
|
|
33
|
+
# Return the current network's IPv6 gateway or nil.
|
34
|
+
def get_ipv6_gateway
|
35
|
+
route6 = Shell.execute('route -A inet6')
|
36
|
+
iface = Context.get.options.core.iface
|
37
|
+
|
38
|
+
Logger.debug "ROUTE6:\n#{route6}"
|
39
|
+
|
40
|
+
route6.split(/\n/).select {|n| n =~ /UG/ }.each do |line|
|
41
|
+
Network::Validator.each_ipv6_gateway(line) do |address|
|
42
|
+
return address
|
43
|
+
end
|
44
|
+
end
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
33
48
|
# Return a list of IP addresses associated to this device network interfaces.
|
34
49
|
def get_local_ips
|
35
50
|
ips = []
|
@@ -77,10 +92,19 @@ class << self
|
|
77
92
|
# Return the hardware address associated with the specified +ip_address+ using
|
78
93
|
# the +iface+ network interface.
|
79
94
|
def get_hw_address( ctx, ip )
|
80
|
-
hw =
|
95
|
+
hw = nil
|
96
|
+
if ctx.options.core.use_ipv6
|
97
|
+
hw = NdpReader.find_address( ip )
|
98
|
+
else
|
99
|
+
hw = ArpReader.find_address( ip )
|
100
|
+
end
|
81
101
|
if hw.nil?
|
82
102
|
start_agents( ctx, ip )
|
83
|
-
|
103
|
+
if ctx.options.core.use_ipv6
|
104
|
+
hw = NdpReader.find_address( ip )
|
105
|
+
else
|
106
|
+
hw = ArpReader.find_address( ip )
|
107
|
+
end
|
84
108
|
end
|
85
109
|
hw
|
86
110
|
end
|
@@ -115,8 +139,12 @@ class << self
|
|
115
139
|
# complete their job.
|
116
140
|
# If +address+ is not nil only that ip will be probed.
|
117
141
|
def start_agents( ctx, address = nil )
|
118
|
-
|
119
|
-
BetterCap::Loader.load("BetterCap::Discovery::Agents
|
142
|
+
if ctx.options.core.use_ipv6
|
143
|
+
BetterCap::Loader.load("BetterCap::Discovery::Agents::Ndp").new(ctx, address)
|
144
|
+
else
|
145
|
+
[ 'Icmp', 'Udp', 'Arp' ].each do |name|
|
146
|
+
BetterCap::Loader.load("BetterCap::Discovery::Agents::#{name}").new(ctx, address)
|
147
|
+
end
|
120
148
|
end
|
121
149
|
ctx.packets.wait_empty( ctx.timeout )
|
122
150
|
end
|
@@ -47,7 +47,7 @@ class Target
|
|
47
47
|
# ip address will be parsed from the computer ARP cache and updated
|
48
48
|
# accordingly.
|
49
49
|
def initialize( ip, mac=nil, network=nil, name=nil )
|
50
|
-
if Network::Validator.is_ip?(ip)
|
50
|
+
if Network::Validator.is_ip?(ip) or Network::Validator.is_ipv6?(ip)
|
51
51
|
@ip = ip
|
52
52
|
@ip_refresh = false
|
53
53
|
elsif Network::Validator.is_mac?(ip)
|
@@ -16,8 +16,28 @@ module Network
|
|
16
16
|
class Validator
|
17
17
|
# Basic expression to validate an IP address.
|
18
18
|
IP_ADDRESS_REGEX = '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})'
|
19
|
+
# Basic expression to validate an IPv6 address.
|
20
|
+
IPV6_REGEX = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|
|
21
|
+
(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|
|
22
|
+
[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]
|
23
|
+
{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]
|
24
|
+
?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:)
|
25
|
+
{4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]
|
26
|
+
\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))
|
27
|
+
|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]
|
28
|
+
{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|
|
29
|
+
1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4})
|
30
|
+
{1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)
|
31
|
+
(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:)
|
32
|
+
{1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|
|
33
|
+
2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))
|
34
|
+
|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|
|
35
|
+
2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))
|
36
|
+
(%.+)?\s*$/x
|
19
37
|
# Quite self explainatory :)
|
20
38
|
IP_OCTECT_MAX = 255
|
39
|
+
# Basic expression for default IPv6 gateway.
|
40
|
+
IPV6_GATEWAY_REGEX = /fe80[^\s]*/
|
21
41
|
|
22
42
|
# Return true if +ip+ is a valid IP address, otherwise false.
|
23
43
|
def self.is_ip?(ip)
|
@@ -27,6 +47,12 @@ class Validator
|
|
27
47
|
false
|
28
48
|
end
|
29
49
|
|
50
|
+
# Return true if +ip+ is a valid IPv6 address, otherwise false.
|
51
|
+
def self.is_ipv6?(ip)
|
52
|
+
result = ip =~ IPV6_REGEX
|
53
|
+
return result ? true : false
|
54
|
+
end
|
55
|
+
|
30
56
|
# Return true if +port+ is a valid port, otherwise false.
|
31
57
|
def self.is_valid_port?(port)
|
32
58
|
port ||= ""
|
@@ -43,6 +69,13 @@ class Validator
|
|
43
69
|
end
|
44
70
|
end
|
45
71
|
|
72
|
+
# Extract default IPv6 gateway address from +data+.
|
73
|
+
def self.each_ipv6_gateway(data)
|
74
|
+
data.scan(/(#{IPV6_GATEWAY_REGEX})/).each do |m|
|
75
|
+
yield ( m[0] )
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
46
79
|
# Return true if +r+ is a valid IP address range ( 192.168.1.1-93 ), otherwise false.
|
47
80
|
def self.is_range?(r)
|
48
81
|
if /\A#{IP_ADDRESS_REGEX}\-(\d{1,3})\Z/ =~ r.to_s
|
@@ -41,6 +41,8 @@ class CoreOptions
|
|
41
41
|
attr_accessor :check_updates
|
42
42
|
# If not nil, the interface MAC address will be changed to this value.
|
43
43
|
attr_accessor :use_mac
|
44
|
+
# If true, IPv6 target endpoints are enabled.
|
45
|
+
attr_accessor :use_ipv6
|
44
46
|
|
45
47
|
def initialize( iface )
|
46
48
|
@iface = iface
|
@@ -56,6 +58,7 @@ class CoreOptions
|
|
56
58
|
@packet_throttle = 0.0
|
57
59
|
@check_updates = false
|
58
60
|
@use_mac = nil
|
61
|
+
@use_ipv6 = false
|
59
62
|
end
|
60
63
|
|
61
64
|
def parse!( ctx, opts )
|
@@ -78,7 +81,7 @@ class CoreOptions
|
|
78
81
|
|
79
82
|
opts.on( '-G', '--gateway ADDRESS', 'Manually specify the gateway address, if not specified the current gateway will be retrieved and used. ' ) do |v|
|
80
83
|
@gateway = v
|
81
|
-
|
84
|
+
check_ip!( v, "The specified gateway '#{v}' is not a valid IPv4 or IPv6 address." )
|
82
85
|
end
|
83
86
|
|
84
87
|
opts.on( '-T', '--target ADDRESS1,ADDRESS2', 'Target IP addresses, if not specified the whole subnet will be targeted.' ) do |v|
|
@@ -147,6 +150,16 @@ class CoreOptions
|
|
147
150
|
raise BetterCap::Error, 'No default interface found, please specify one with the -I argument.' if @iface.nil?
|
148
151
|
end
|
149
152
|
|
153
|
+
def check_ip!(v,error)
|
154
|
+
if Network::Validator.is_ip?(v)
|
155
|
+
@use_ipv6 = false
|
156
|
+
elsif Network::Validator.is_ipv6?(v)
|
157
|
+
@use_ipv6 = true
|
158
|
+
else
|
159
|
+
raise BetterCap::Error, error
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
150
163
|
# Return true if active host discovery is enabled, otherwise false.
|
151
164
|
def discovery?
|
152
165
|
( @discovery and @targets.nil? )
|
@@ -161,6 +174,10 @@ class CoreOptions
|
|
161
174
|
if Network::Validator.is_ip?(t) or Network::Validator.is_mac?(t)
|
162
175
|
@targets << Network::Target.new(t)
|
163
176
|
|
177
|
+
elsif Network::Validator.is_ipv6?(t)
|
178
|
+
@targets << Network::Target.new(t)
|
179
|
+
@use_ipv6 = true
|
180
|
+
|
164
181
|
elsif Network::Validator.is_range?(t)
|
165
182
|
Network::Validator.each_in_range( t ) do |address|
|
166
183
|
@targets << Network::Target.new(address)
|
@@ -172,7 +189,7 @@ class CoreOptions
|
|
172
189
|
end
|
173
190
|
|
174
191
|
else
|
175
|
-
raise BetterCap::Error, "Invalid target specified '#{t}', valid formats are IP addresses, "\
|
192
|
+
raise BetterCap::Error, "Invalid target specified '#{t}', valid formats are IP/IPv6 addresses, "\
|
176
193
|
"MAC addresses, IP ranges ( 192.168.1.1-30 ) or netmasks ( 192.168.1.1/24 ) ."
|
177
194
|
end
|
178
195
|
end
|
@@ -182,7 +199,7 @@ class CoreOptions
|
|
182
199
|
# or more invalid IP addresses are specified.
|
183
200
|
def ignore=(value)
|
184
201
|
@ignore = value.split(",")
|
185
|
-
valid = @ignore.select { |target| Network::Validator.is_ip?(target) }
|
202
|
+
valid = @ignore.select { |target| ( Network::Validator.is_ip?(target) or Network::Validator.is_ipv6?(target) ) }
|
186
203
|
|
187
204
|
raise BetterCap::Error, "Invalid ignore addresses specified." if valid.empty?
|
188
205
|
|
@@ -191,6 +208,12 @@ class CoreOptions
|
|
191
208
|
Logger.warn "Not a valid address: #{target}"
|
192
209
|
end
|
193
210
|
|
211
|
+
valid.each do |target|
|
212
|
+
if Network::Validator.is_ipv6?(target)
|
213
|
+
@use_ipv6 = true
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
194
217
|
@ignore = valid
|
195
218
|
|
196
219
|
Logger.warn "Ignoring #{valid.join(", ")} ."
|
@@ -125,6 +125,10 @@ class Options
|
|
125
125
|
redirections << redir_single( @proxies.tcp_proxy_upstream_address, iface.ip, @proxies.tcp_proxy_upstream_port, @proxies.tcp_proxy_port )
|
126
126
|
end
|
127
127
|
|
128
|
+
if @proxies.udp_proxy
|
129
|
+
redirections << redir_single( @proxies.udp_proxy_upstream_address, iface.ip, @proxies.udp_proxy_upstream_port, @proxies.udp_proxy_port, 'UDP' )
|
130
|
+
end
|
131
|
+
|
128
132
|
if @proxies.custom_proxy
|
129
133
|
@proxies.http_ports.each do |port|
|
130
134
|
redirections << redir( @proxies.custom_proxy, port, @proxies.custom_proxy_port )
|
@@ -153,6 +157,7 @@ class Options
|
|
153
157
|
'discovery' => ( @core.discovery? ? on : off ),
|
154
158
|
'sniffer' => ( @sniff.enabled? ? on : off ),
|
155
159
|
'tcp-proxy' => ( @proxies.tcp_proxy ? on : off ),
|
160
|
+
'udp-proxy' => ( @proxies.udp_proxy ? on : off ),
|
156
161
|
'http-proxy' => ( @proxies.proxy ? on : off ),
|
157
162
|
'https-proxy' => ( @proxies.proxy_https ? on : off ),
|
158
163
|
'sslstrip' => ( @proxies.sslstrip? ? on : off ),
|
@@ -40,6 +40,7 @@ class ProxyOptions
|
|
40
40
|
attr_accessor :log_response
|
41
41
|
# If true, suppress HTTP requests logs.
|
42
42
|
attr_accessor :no_http_logs
|
43
|
+
|
43
44
|
# If true, TCP proxy will be enabled.
|
44
45
|
attr_accessor :tcp_proxy
|
45
46
|
# TCP proxy local port.
|
@@ -50,6 +51,18 @@ class ProxyOptions
|
|
50
51
|
attr_accessor :tcp_proxy_upstream_port
|
51
52
|
# TCP proxy module to load.
|
52
53
|
attr_accessor :tcp_proxy_module
|
54
|
+
|
55
|
+
# If true, UDP proxy will be enabled.
|
56
|
+
attr_accessor :udp_proxy
|
57
|
+
# UDP proxy local port.
|
58
|
+
attr_accessor :udp_proxy_port
|
59
|
+
# UDP proxy upstream server address.
|
60
|
+
attr_accessor :udp_proxy_upstream_address
|
61
|
+
# UDP proxy upstream server port.
|
62
|
+
attr_accessor :udp_proxy_upstream_port
|
63
|
+
# UDP proxy module to load.
|
64
|
+
attr_accessor :udp_proxy_module
|
65
|
+
|
53
66
|
# Custom HTTP transparent proxy address.
|
54
67
|
attr_accessor :custom_proxy
|
55
68
|
# Custom HTTP transparent proxy port.
|
@@ -82,6 +95,12 @@ class ProxyOptions
|
|
82
95
|
@tcp_proxy_upstream_port = nil
|
83
96
|
@tcp_proxy_module = nil
|
84
97
|
|
98
|
+
@udp_proxy = false
|
99
|
+
@udp_proxy_port = 3333
|
100
|
+
@udp_proxy_upstream_address = nil
|
101
|
+
@udp_proxy_upstream_port = nil
|
102
|
+
@udp_proxy_module = nil
|
103
|
+
|
85
104
|
@custom_proxy = nil
|
86
105
|
@custom_proxy_port = 8080
|
87
106
|
|
@@ -143,6 +162,53 @@ class ProxyOptions
|
|
143
162
|
@tcp_proxy_upstream_port = v.to_i
|
144
163
|
end
|
145
164
|
|
165
|
+
opts.separator ""
|
166
|
+
opts.separator " UDP:"
|
167
|
+
opts.separator ""
|
168
|
+
|
169
|
+
opts.on( '--udp-proxy', 'Enable UDP proxy ( requires other --udp-proxy-* options to be specified ).' ) do
|
170
|
+
@udp_proxy = true
|
171
|
+
end
|
172
|
+
|
173
|
+
opts.on( '--udp-proxy-module MODULE', "Ruby UDP proxy module to load." ) do |v|
|
174
|
+
@udp_proxy_module = File.expand_path(v)
|
175
|
+
Proxy::UDP::Module.load( @udp_proxy_module, opts )
|
176
|
+
end
|
177
|
+
|
178
|
+
opts.on( '--udp-proxy-port PORT', "Set local UDP proxy port, default to #{@udp_proxy_port.to_s.yellow} ." ) do |v|
|
179
|
+
raise BetterCap::Error, "Invalid port '#{v}' specified." unless Network::Validator.is_valid_port?(v)
|
180
|
+
@udp_proxy = true
|
181
|
+
@udp_proxy_port = v.to_i
|
182
|
+
end
|
183
|
+
|
184
|
+
opts.on( '--udp-proxy-upstream ADDRESS:PORT', 'Set UDP proxy upstream server address and port.' ) do |v|
|
185
|
+
if v =~ /^(.+):(\d+)$/
|
186
|
+
address = $1
|
187
|
+
port = $2
|
188
|
+
else
|
189
|
+
raise BetterCap::Error, "Invalid address and port specified, the correct syntax is ADDRESS:PORT ( i.e. 192.168.1.2:69 )."
|
190
|
+
end
|
191
|
+
|
192
|
+
address, port = validate_address address, port
|
193
|
+
|
194
|
+
@udp_proxy = true
|
195
|
+
@udp_proxy_upstream_address = address
|
196
|
+
@udp_proxy_upstream_port = port.to_i
|
197
|
+
end
|
198
|
+
|
199
|
+
opts.on( '--udp-proxy-upstream-address ADDRESS', 'Set UDP proxy upstream server address.' ) do |v|
|
200
|
+
v, _ = validate_address v
|
201
|
+
|
202
|
+
@udp_proxy = true
|
203
|
+
@udp_proxy_upstream_address = v
|
204
|
+
end
|
205
|
+
|
206
|
+
opts.on( '--udp-proxy-upstream-port PORT', 'Set UDP proxy upstream server port.' ) do |v|
|
207
|
+
raise BetterCap::Error, "Invalid port '#{v}' specified." unless Network::Validator.is_valid_port?(v)
|
208
|
+
@udp_proxy = true
|
209
|
+
@udp_proxy_upstream_port = v.to_i
|
210
|
+
end
|
211
|
+
|
146
212
|
opts.separator " HTTP:"
|
147
213
|
opts.separator ""
|
148
214
|
|
@@ -245,6 +311,12 @@ class ProxyOptions
|
|
245
311
|
raise BetterCap::Error, "No TCP proxy upstream server port specified ( --tcp-proxy-upstream-port PORT )." if @tcp_proxy_upstream_port.nil?
|
246
312
|
end
|
247
313
|
|
314
|
+
if @udp_proxy
|
315
|
+
raise BetterCap::Error, "No UDP proxy port specified ( --udp-proxy-port PORT )." if @udp_proxy_port.nil?
|
316
|
+
raise BetterCap::Error, "No UDP proxy upstream server address specified ( --udp-proxy-upstream-address ADDRESS )." if @udp_proxy_upstream_address.nil?
|
317
|
+
raise BetterCap::Error, "No UDP proxy upstream server port specified ( --udp-proxy-upstream-port PORT )." if @udp_proxy_upstream_port.nil?
|
318
|
+
end
|
319
|
+
|
248
320
|
if @proxy and @sslstrip and ctx.options.servers.dnsd
|
249
321
|
raise BetterCap::Error, "SSL Stripping and builtin DNS server are mutually exclusive features, " \
|
250
322
|
"either use the --no-sslstrip option or remove the --dns option."
|
@@ -305,7 +377,7 @@ class ProxyOptions
|
|
305
377
|
end
|
306
378
|
|
307
379
|
def any?
|
308
|
-
@proxy or @proxy_https or @tcp_proxy or @custom_proxy
|
380
|
+
@proxy or @proxy_https or @tcp_proxy or @udp_proxy or @custom_proxy
|
309
381
|
end
|
310
382
|
|
311
383
|
def validate_address( address, port = nil )
|
@@ -33,7 +33,7 @@ class SpoofOptions
|
|
33
33
|
opts.separator "SPOOFING:".bold
|
34
34
|
opts.separator ""
|
35
35
|
|
36
|
-
opts.on( '-S', '--spoofer NAME', "Spoofer module to use, available: #{Spoofers::Base.available.map{|x| x.yellow }.join(', ')} - default: #{@spoofer.yellow}." ) do |v|
|
36
|
+
opts.on( '-S', '--spoofer NAME', "Spoofer module to use, available: #{Spoofers::Base.available.map{|x| x.yellow }.join(', ')} - default: #{@spoofer.yellow} for IPv4 and #{'NDP'.yellow} for IPv6." ) do |v|
|
37
37
|
@spoofer = v
|
38
38
|
end
|
39
39
|
|
@@ -55,11 +55,19 @@ class SpoofOptions
|
|
55
55
|
@spoofer.upcase != 'NONE'
|
56
56
|
end
|
57
57
|
|
58
|
+
# Change default ARP with NDP spoofer in case the target endpoint uses IPv6.
|
59
|
+
def calibrate_default_spoofer(ctx)
|
60
|
+
if ctx.options.core.use_ipv6
|
61
|
+
@spoofer = 'NDP'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
58
65
|
|
59
66
|
# Parse spoofers and return a list of BetterCap::Spoofers objects. Raise a
|
60
67
|
# BetterCap::Error if an invalid spoofer name was specified.
|
61
|
-
def parse_spoofers
|
68
|
+
def parse_spoofers(ctx)
|
62
69
|
valid = []
|
70
|
+
calibrate_default_spoofer(ctx)
|
63
71
|
@spoofer.split(",").each do |module_name|
|
64
72
|
valid << Spoofers::Base.get_by_name( module_name )
|
65
73
|
end
|
@@ -62,7 +62,12 @@ class Proxy
|
|
62
62
|
# Start this proxy instance.
|
63
63
|
def start
|
64
64
|
begin
|
65
|
-
|
65
|
+
# If IPv6 is enabled, we must specify iface for current link local address since it's not unique.
|
66
|
+
if Context.get.options.core.use_ipv6
|
67
|
+
@socket = TCPServer.new( @address + "%" + Context.get.options.core.iface , @port )
|
68
|
+
else
|
69
|
+
@socket = TCPServer.new( @address, @port )
|
70
|
+
end
|
66
71
|
|
67
72
|
if @is_https
|
68
73
|
@sslserver = SSL::Server.new( @socket, @upstream_port )
|
@@ -64,7 +64,7 @@ class Response
|
|
64
64
|
end
|
65
65
|
|
66
66
|
r << "Connection: close"
|
67
|
-
r << "\n\n"
|
67
|
+
r << "\r\n\r\n"
|
68
68
|
|
69
69
|
r
|
70
70
|
end
|
@@ -225,7 +225,13 @@ class Response
|
|
225
225
|
s << "#{name}: #{value}\n"
|
226
226
|
end
|
227
227
|
end
|
228
|
-
s << "\
|
228
|
+
s << "\r\n"
|
229
|
+
|
230
|
+
if @body.nil?
|
231
|
+
s << "\r\n"
|
232
|
+
else
|
233
|
+
s << @body
|
234
|
+
end
|
229
235
|
s
|
230
236
|
end
|
231
237
|
end
|
@@ -1,52 +1,56 @@
|
|
1
1
|
-----BEGIN RSA PRIVATE KEY-----
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
2
|
+
MIIEpAIBAAKCAQEAw47NyTN8vMZjyhG3oLRYTrnxJChFZ8TO4nPoYWupox2TTg6s
|
3
|
+
FvvM9KI92gz/Y4WRdk317ih2uWx7WyU5cQ+D3S5xDpMGtqHAiAnHQg66G1hmM4a3
|
4
|
+
s2EPDLWd++j8TMr9DgBHwsOXVw70IQ0xQT9THZEMHa92kxcXQ2kFTW5EjPi7hzBW
|
5
|
+
a+V3yXuMCnwVOzC+DFAu9LHwHEv4Kc96u2j4/PQO1813QINCmKqCP/oUh84Dz4Pm
|
6
|
+
JIYhCtoleKYdyXR1y9O3hngjl3mIyu0J8IoToglTwWMrBmqKy57BHZDC1XVxLyHT
|
7
|
+
7f9cZBrWGV4nDRm72PJFL0KV2e0M+kHj2y+VwwIDAQABAoIBABMddFQEal7xbXOl
|
8
|
+
A7P7rN4VItML9KzN+gL8nWxYX76H94wbtwqQFlqbOTyFJLmPpsZPnIhpACHjzrL8
|
9
|
+
En9Qqu0FyxtHl9JmQTGK8yUr11kw7NyAgJhSFmyBnC2xemfvN4kU0e7hu3tRBN/u
|
10
|
+
MDBWhkNPmEWWjxqVmTqHm3MUIjM9OQMwezFf+HwcudLM9QRVSOX9oNUw2wcjqqJG
|
11
|
+
rr3kMuOm3BHUeFhCYnv7VltnUNvnC3hbm2qNbu3yYYjioKRKMpdaHInlmnoTMwsi
|
12
|
+
7cp5QjBStMtSuGf6/nDBHy/wr/yu40lxI2oL6jFMxq6utT0/rQ1UHSMRIOF5MlXn
|
13
|
+
NfLrqcECgYEA8ws3WGhVSY0LkO2oZsnnzuHzBg/Mcl6QVn9TfndTG6h/PGWCI0Mj
|
14
|
+
7GhsoPDFwBVaRG0iIaqrAdxZ6YmZ2p15SdDEkcVDBGmcLcT2jO5E6S4G06oWlvSq
|
15
|
+
G37QdzsNj685UPqCWjaUGtOK9IHegCVKwwYbQ+ra3ze6kfsuQq4V6FECgYEAzfuN
|
16
|
+
ozmLylORO3ihLRJ7UVepDj8Qe2xr4Bb4TuKy90/AM9j59RbrVe8cI2C4mGokzoOW
|
17
|
+
cndsmyuSPOwVjXcoNt5WhmJAN2jISmKtUd+KbzSX6mPjAhkg96mJUMu9JfyjjM+A
|
18
|
+
MMcH+shPn0aPFKT0XWi7knGh0i8Fpm6CpsQDq9MCgYEAyU7yAaUxd2F/QgTHppP4
|
19
|
+
EFDwpYWydszCyxJdivO0/8S51sHRX/m9qJP53fhwIyDMir7GNZKSYFEunBRgPkaO
|
20
|
+
7sgf+Qml7+K1/OcWvDajF20LNIi+ezyeJXYNn6RnICsn014bWDO6ytmLT+i97fB1
|
21
|
+
k0HclY3Sym7zdvTRJWPiO3ECgYEApbe6bhWAJ9kvwP79/Psfh4PVGQcXxZSm/XS9
|
22
|
+
dQniHiJladEo2EwGLe7fXn8URFsxHYy0X4dBM13Mm4L8nAG/stUSG6+0JmAAtAfL
|
23
|
+
lVEZWPqhNgwCuM9qvJYDSaOAm600D7dpVNTr0JGTrXrg5iUIDJaUQe9111nJW+sQ
|
24
|
+
5gZRRc0CgYAc4s81tYhldDH4z2tkCIpJpir6YNtYAPvc7MaIwyBIvixlQzKWhLac
|
25
|
+
am0oqnBMUwPPpwvcfMfFDdgGJFeioK0oaFmaVhKYqNM9v5ZlsuUlONE8TOcA2f6g
|
26
|
+
gNc7NAONgg/7Bj0NgkKWpfLGVntDYSrsnDsdgifUWUC9Nge1RCqeOg==
|
27
27
|
-----END RSA PRIVATE KEY-----
|
28
28
|
-----BEGIN CERTIFICATE-----
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
29
|
+
MIIFDDCCA/SgAwIBAgIJAKgmMGmQctr/MA0GCSqGSIb3DQEBBQUAMIG0MQswCQYD
|
30
|
+
VQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEa
|
31
|
+
MBgGA1UEChMRR29EYWRkeS5jb20sIEluYy4xLTArBgNVBAsTJGh0dHA6Ly9jZXJ0
|
32
|
+
cy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzEzMDEGA1UEAxMqR28gRGFkZHkgU2Vj
|
33
|
+
dXJlIENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTE3MDYyOTE3MTMwNFoX
|
34
|
+
DTI3MDYyNzE3MTMwNFowgbQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25h
|
35
|
+
MRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5j
|
36
|
+
LjEtMCsGA1UECxMkaHR0cDovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkv
|
37
|
+
MTMwMQYDVQQDEypHbyBEYWRkeSBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
|
38
|
+
IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDjs3JM3y8xmPK
|
39
|
+
EbegtFhOufEkKEVnxM7ic+hha6mjHZNODqwW+8z0oj3aDP9jhZF2TfXuKHa5bHtb
|
40
|
+
JTlxD4PdLnEOkwa2ocCICcdCDrobWGYzhrezYQ8MtZ376PxMyv0OAEfCw5dXDvQh
|
41
|
+
DTFBP1MdkQwdr3aTFxdDaQVNbkSM+LuHMFZr5XfJe4wKfBU7ML4MUC70sfAcS/gp
|
42
|
+
z3q7aPj89A7XzXdAg0KYqoI/+hSHzgPPg+YkhiEK2iV4ph3JdHXL07eGeCOXeYjK
|
43
|
+
7QnwihOiCVPBYysGaorLnsEdkMLVdXEvIdPt/1xkGtYZXicNGbvY8kUvQpXZ7Qz6
|
44
|
+
QePbL5XDAgMBAAGjggEdMIIBGTAdBgNVHQ4EFgQUo9Vx+QWZ9ce2K873Xxklfi2J
|
45
|
+
Q+owgekGA1UdIwSB4TCB3oAUo9Vx+QWZ9ce2K873Xxklfi2JQ+qhgbqkgbcwgbQx
|
46
|
+
CzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNk
|
47
|
+
YWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEtMCsGA1UECxMkaHR0cDov
|
48
|
+
L2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMwMQYDVQQDEypHbyBEYWRk
|
49
|
+
eSBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzKCCQCoJjBpkHLa/zAM
|
50
|
+
BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCKe6sCMJ52wAKrv2uKXuep
|
51
|
+
qj+epzXB8zTO4z2QcoreUAITEQSqfGjgtyWHM9jqZ8kq97d9KG9M/dp5YCpoAecj
|
52
|
+
kn3uweywUIXvyQqazP14KLJh+1W/DuGkzaEJFWbOMuTzE64QSyZ4NM/DW+hbdAls
|
53
|
+
1k5zBVZH91qGczpsO1b//+pPFdPMtGJCFm+U1Mh7BzS5KZjsEEEDUO3trT1hP2qF
|
54
|
+
9UJr22RZyTI595RW7JTbDaMTT7aTqHD58a6U2Lc2Au6YK0XiajBViqit0XnU2K2K
|
55
|
+
2TXj8TpZ+v6O9X/ryYbr4Et4S6B4ljPuNo3CMyj3YPV29IoxNndg7zTHZCXJ3Lxh
|
52
56
|
-----END CERTIFICATE-----
|