bettercap 1.4.6 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/bettercap +1 -1
- data/lib/bettercap.rb +1 -0
- data/lib/bettercap/context.rb +63 -70
- data/lib/bettercap/discovery/agents/base.rb +2 -2
- data/lib/bettercap/discovery/thread.rb +5 -4
- data/lib/bettercap/firewalls/base.rb +2 -4
- data/lib/bettercap/firewalls/{osx.rb → bsd.rb} +3 -3
- data/lib/bettercap/firewalls/linux.rb +2 -2
- data/lib/bettercap/firewalls/redirection.rb +5 -2
- data/lib/bettercap/logger.rb +6 -11
- data/lib/bettercap/memory.rb +56 -0
- data/lib/bettercap/monkey/em-proxy/proxy.rb +23 -0
- data/lib/bettercap/monkey/packetfu/pcap.rb +51 -0
- data/lib/bettercap/network/arp_reader.rb +2 -2
- data/lib/bettercap/network/network.rb +2 -2
- data/lib/bettercap/network/packet_queue.rb +2 -2
- data/lib/bettercap/network/protos/base.rb +8 -5
- data/lib/bettercap/network/protos/dhcp.rb +5 -124
- data/lib/bettercap/network/target.rb +7 -2
- data/lib/bettercap/options/core_options.rb +189 -0
- data/lib/bettercap/options/options.rb +167 -0
- data/lib/bettercap/options/proxy_options.rb +258 -0
- data/lib/bettercap/options/server_options.rb +71 -0
- data/lib/bettercap/options/sniff_options.rb +90 -0
- data/lib/bettercap/options/spoof_options.rb +71 -0
- data/lib/bettercap/proxy/{module.rb → http/module.rb} +8 -4
- data/lib/bettercap/proxy/{modules → http/modules}/injectcss.rb +2 -2
- data/lib/bettercap/proxy/{modules → http/modules}/injecthtml.rb +2 -2
- data/lib/bettercap/proxy/{modules → http/modules}/injectjs.rb +2 -2
- data/lib/bettercap/proxy/{proxy.rb → http/proxy.rb} +5 -2
- data/lib/bettercap/proxy/{request.rb → http/request.rb} +4 -0
- data/lib/bettercap/proxy/{response.rb → http/response.rb} +3 -0
- data/lib/bettercap/proxy/{ssl → http/ssl}/authority.rb +3 -1
- data/lib/bettercap/proxy/{ssl → http/ssl}/bettercap-ca.pem +0 -0
- data/lib/bettercap/proxy/{ssl → http/ssl}/server.rb +3 -1
- data/lib/bettercap/proxy/{sslstrip → http/sslstrip}/cookiemonitor.rb +2 -0
- data/lib/bettercap/proxy/{sslstrip → http/sslstrip}/lock.ico +0 -0
- data/lib/bettercap/proxy/{sslstrip → http/sslstrip}/strip.rb +4 -2
- data/lib/bettercap/proxy/{streamer.rb → http/streamer.rb} +7 -4
- data/lib/bettercap/proxy/stream_logger.rb +25 -9
- data/lib/bettercap/proxy/tcp/module.rb +75 -0
- data/lib/bettercap/proxy/tcp/proxy.rb +123 -0
- data/lib/bettercap/proxy/thread_pool.rb +1 -1
- data/lib/bettercap/sniffer/parsers/post.rb +1 -1
- data/lib/bettercap/sniffer/parsers/url.rb +1 -1
- data/lib/bettercap/sniffer/sniffer.rb +23 -17
- data/lib/bettercap/spoofers/arp.rb +21 -9
- data/lib/bettercap/spoofers/base.rb +12 -16
- data/lib/bettercap/spoofers/icmp.rb +4 -5
- data/lib/bettercap/spoofers/none.rb +0 -1
- data/lib/bettercap/version.rb +1 -1
- metadata +48 -19
- data/lib/bettercap/firewalls/openbsd.rb +0 -77
- data/lib/bettercap/options.rb +0 -600
@@ -0,0 +1,23 @@
|
|
1
|
+
class Proxy
|
2
|
+
|
3
|
+
def self.start(options, &blk)
|
4
|
+
# epoll is not supported on OSX!
|
5
|
+
# EM.epoll
|
6
|
+
EM.run do
|
7
|
+
# We'll take care of this.
|
8
|
+
#
|
9
|
+
# trap("TERM") { stop }
|
10
|
+
# trap("INT") { stop }
|
11
|
+
|
12
|
+
EventMachine::start_server(options[:host], options[:port],
|
13
|
+
EventMachine::ProxyServer::Connection, options) do |c|
|
14
|
+
c.instance_eval(&blk)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.stop
|
20
|
+
EventMachine.stop
|
21
|
+
rescue
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
=begin
|
3
|
+
|
4
|
+
BETTERCAP
|
5
|
+
|
6
|
+
Author : Simone 'evilsocket' Margaritelli
|
7
|
+
Email : evilsocket@gmail.com
|
8
|
+
Blog : http://www.evilsocket.net/
|
9
|
+
|
10
|
+
This project is released under the GPL 3 license.
|
11
|
+
|
12
|
+
=end
|
13
|
+
module PacketFu
|
14
|
+
|
15
|
+
class PcapHeader
|
16
|
+
# Reads a string to populate the object.
|
17
|
+
# Conversion from big to little shouldn't be that big of a deal.
|
18
|
+
def read(str)
|
19
|
+
force_binary(str)
|
20
|
+
return self if str.nil?
|
21
|
+
str.force_encoding(Encoding::BINARY) if str.respond_to? :force_encoding
|
22
|
+
|
23
|
+
# Handle little endian pcap
|
24
|
+
if str[0,4] == self[:magic].to_s
|
25
|
+
self[:magic].read str[0,4]
|
26
|
+
self[:ver_major].read str[4,2]
|
27
|
+
self[:ver_minor].read str[6,2]
|
28
|
+
self[:thiszone].read str[8,4]
|
29
|
+
self[:sigfigs].read str[12,4]
|
30
|
+
self[:snaplen].read str[16,4]
|
31
|
+
self[:network].read str[20,4]
|
32
|
+
# Handle big endian pcap
|
33
|
+
elsif str[0,4] == MAGIC_BIG.to_s
|
34
|
+
# Since PcapFile.read uses our endianess, set it to 'big' anyway.
|
35
|
+
self[:endian] = :big
|
36
|
+
|
37
|
+
self[:magic].read str[0,4].reverse
|
38
|
+
self[:ver_major].read str[4,2].reverse
|
39
|
+
self[:ver_minor].read str[6,2].reverse
|
40
|
+
self[:thiszone].read str[8,4].reverse
|
41
|
+
self[:sigfigs].read str[12,4].reverse
|
42
|
+
self[:snaplen].read str[16,4].reverse
|
43
|
+
self[:network].read str[20,4].reverse
|
44
|
+
else
|
45
|
+
raise "Incorrect magic for libpcap"
|
46
|
+
end
|
47
|
+
self
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -21,8 +21,8 @@ class ArpReader
|
|
21
21
|
def self.parse( ctx )
|
22
22
|
targets = []
|
23
23
|
self.parse_cache do |ip,mac|
|
24
|
-
if ip != ctx.gateway and ip != ctx.ifconfig[:ip_saddr]
|
25
|
-
if ctx.options.ignore_ip?(ip)
|
24
|
+
if ip != ctx.gateway.ip and ip != ctx.ifconfig[:ip_saddr]
|
25
|
+
if ctx.options.core.ignore_ip?(ip)
|
26
26
|
Logger.debug "Ignoring #{ip} ..."
|
27
27
|
else
|
28
28
|
# reuse Target object if it's already a known address
|
@@ -18,7 +18,7 @@ class << self
|
|
18
18
|
# Return the current network gateway or nil.
|
19
19
|
def get_gateway
|
20
20
|
nstat = Shell.execute('netstat -nr')
|
21
|
-
iface = Context.get.options.iface
|
21
|
+
iface = Context.get.options.core.iface
|
22
22
|
|
23
23
|
Logger.debug "NETSTAT:\n#{nstat}"
|
24
24
|
|
@@ -54,7 +54,7 @@ class << self
|
|
54
54
|
# Return a list of BetterCap::Target objects found on the network, given a
|
55
55
|
# BetterCap::Context ( +ctx+ ) and a +timeout+ in seconds for the operation.
|
56
56
|
def get_alive_targets( ctx )
|
57
|
-
if ctx.options.should_discover_hosts?
|
57
|
+
if ctx.options.core.should_discover_hosts?
|
58
58
|
start_agents( ctx )
|
59
59
|
else
|
60
60
|
Logger.debug 'Using current ARP cache.'
|
@@ -29,13 +29,13 @@ class PacketQueue
|
|
29
29
|
@udp = UDPSocket.new
|
30
30
|
@queue = Queue.new
|
31
31
|
@workers = (0...nworkers).map { ::Thread.new { worker } }
|
32
|
+
@ctx = Context.get
|
32
33
|
end
|
33
34
|
|
34
35
|
# Push a packet to the queue.
|
35
36
|
def push(packet)
|
36
|
-
Context.run_gc if @queue.size == 0
|
37
|
-
|
38
37
|
@queue.push(packet)
|
38
|
+
@ctx.memory.optimize! if ( @queue.size == 1 )
|
39
39
|
end
|
40
40
|
|
41
41
|
# Wait for the packet queue to be empty.
|
@@ -98,11 +98,6 @@ class Base
|
|
98
98
|
offset = offset( info, pkt, offset )
|
99
99
|
|
100
100
|
value = data[offset..offset + size - 1].bytes.pack('c*')
|
101
|
-
if info[:opts].has_key?(:check)
|
102
|
-
if value != info[:opts][:check].force_encoding('ASCII-8BIT')
|
103
|
-
raise "Unexpected value '#{value}', expected '#{info[:opts][:check]}' ."
|
104
|
-
end
|
105
|
-
end
|
106
101
|
offset += size
|
107
102
|
|
108
103
|
when :stringz
|
@@ -116,6 +111,14 @@ class Base
|
|
116
111
|
|
117
112
|
end
|
118
113
|
|
114
|
+
if info[:opts].has_key?(:check)
|
115
|
+
check = info[:opts][:check]
|
116
|
+
check = check.force_encoding('ASCII-8BIT') if check.respond_to? :force_encoding
|
117
|
+
if value != check
|
118
|
+
raise "Unexpected value '#{value}', expected '#{check}' ."
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
119
122
|
pkt.send("#{name}=", value)
|
120
123
|
end
|
121
124
|
|
@@ -28,125 +28,6 @@ OP_MESSAGETYPES = {
|
|
28
28
|
}
|
29
29
|
|
30
30
|
OP_CONSTANTS = {
|
31
|
-
# DHCP Options
|
32
|
-
:DHCPPad => 0,
|
33
|
-
:DHCPSubnetMask => 1,
|
34
|
-
:DHCPTimeOffset => 2,
|
35
|
-
:DHCPRouter => 3,
|
36
|
-
:DHCPTimeServer => 4,
|
37
|
-
:DHCPNameServer => 5,
|
38
|
-
:DHCPDNS => 6,
|
39
|
-
:DHCPLogServer => 7,
|
40
|
-
:DHCPQuoteServer => 8,
|
41
|
-
:DHCPLPRServer => 9,
|
42
|
-
:DHCPImpressServer => 10,
|
43
|
-
:DHCPRLServer => 11,
|
44
|
-
:DHCPHostName => 12,
|
45
|
-
:DHCPBootFileSize => 13,
|
46
|
-
:DHCPMeritDumpFile => 14,
|
47
|
-
:DHCPDomainName => 15,
|
48
|
-
:DHCPSwapServer => 16,
|
49
|
-
:DHCPRootPath => 17,
|
50
|
-
:DHCPExtensionsPath => 18,
|
51
|
-
:DHCPIPForwarding => 19,
|
52
|
-
:DHCPNonLocalRouting => 20,
|
53
|
-
:DHCPPolicyFilter => 21,
|
54
|
-
:DHCPMaximumDRSize => 22, # Datagram reassembly size
|
55
|
-
:DHCPDefaultIPTTL => 23,
|
56
|
-
:DHCPPathMTUAgingTimeout => 24,
|
57
|
-
:DHCPPathMTUPlateauTable => 25,
|
58
|
-
:DHCPInterfaceMTU => 26,
|
59
|
-
:DHCPAllSubnetsLocal => 27,
|
60
|
-
:DHCPBroadcastAddress => 28,
|
61
|
-
:DHCPPerformMask => 29, # Perform mask discovery
|
62
|
-
:DHCPMaskSupplier => 30, # Zelda flashbacks
|
63
|
-
:DHCPPerformRouter => 31, # Perform router discovery
|
64
|
-
:DHCPRouterSolicitation => 32, # Router Solicitation Address
|
65
|
-
:DHCPStaticRoutingEnable => 33,
|
66
|
-
:DHCPTrailerEncap => 34, # Trailer Encapsulation
|
67
|
-
:DHCPArpCacheTimeout => 35,
|
68
|
-
:DHCPEthernetEncap => 36, # ethernet encapsulation
|
69
|
-
:DHCPDefaultTCPTTL => 37,
|
70
|
-
:DHCPTCPKeepAliveInt => 38, # TCP Keepalive interval
|
71
|
-
:DHCPTCPKeepAliveGB => 39, # TCP Keepalive garbage
|
72
|
-
:DHCPNISDomain => 40,
|
73
|
-
:DHCPNISServer => 41,
|
74
|
-
:DHCPNTPServers => 42,
|
75
|
-
:DHCPVendorSpecificInfo => 43,
|
76
|
-
:DHCPNetBIOSNameServer => 44,
|
77
|
-
:DHCPNetBIOSDDS => 45,
|
78
|
-
:DHCPNetBIOSNodeType => 46,
|
79
|
-
:DHCPNetBIOSScope => 47,
|
80
|
-
:DHCPXWindowSystemFont => 48, # XWindow Font server
|
81
|
-
:DHCPXWindowSystemDM => 49, # Xwindow System Display Server
|
82
|
-
:DHCPRequestedIPAddress => 50,
|
83
|
-
:DHCPIPAddressLeaseTime => 51,
|
84
|
-
:DHCPOptionOverload => 52,
|
85
|
-
:DHCPMessageType => 53,
|
86
|
-
:DHCPServerIdentifier => 54,
|
87
|
-
:DHCPParameters => 55,
|
88
|
-
:DHCPMessage => 56,
|
89
|
-
:DHCPMaxDHCPMessageSize => 57,
|
90
|
-
:DHCPRenewTimeValue => 58,
|
91
|
-
:DHCPRebindingTimeValue => 59,
|
92
|
-
:DHCPClassIdentifier => 60,
|
93
|
-
:DHCPClientIdentifier => 61,
|
94
|
-
:DHCPNetWareIPDomainName => 62,
|
95
|
-
:DHCPNetWareIPInformation => 63,
|
96
|
-
:DHCPNISClientDomain => 64,
|
97
|
-
:DHCPNISServers => 65,
|
98
|
-
:DHCPTFTPServerName => 66,
|
99
|
-
:DHCPBootFileName => 67,
|
100
|
-
:DHCPMobileIPHomeAgent => 68,
|
101
|
-
:DHCPSMTPServer => 69,
|
102
|
-
:DHCPPOPServer => 70,
|
103
|
-
:DHCPNNTPServer => 71,
|
104
|
-
:DHCPDefaultWWWServer => 72,
|
105
|
-
:DHCPDefaultFingerServer => 73,
|
106
|
-
:DHCPDefaultIRCServer => 74,
|
107
|
-
:DHCPStreetTalkServer => 75,
|
108
|
-
:DHCPStreetTalkDAS => 76,
|
109
|
-
:DHCPUserClassInformation => 77,
|
110
|
-
:DHCPSLPDirectoryAgent => 78,
|
111
|
-
:DHCPSLPServiceScope => 79,
|
112
|
-
:DHCPRapidCommit => 80,
|
113
|
-
:DHCPFQDN => 81,
|
114
|
-
:DHCPRelayAgentInformation => 82,
|
115
|
-
:DHCPInternetStorageNameService => 83,
|
116
|
-
# ??
|
117
|
-
:DHCPNDSServers => 85,
|
118
|
-
:DHCPNDSTreeName => 86,
|
119
|
-
:DHCPNDSContext => 87,
|
120
|
-
:DHCPBCMCSContDomainNameList => 88,
|
121
|
-
:DHCPBCMCSContIPV4AddressList => 89,
|
122
|
-
:DHCPAuthentication => 90,
|
123
|
-
:DHCPClientLastTransactTime => 91,
|
124
|
-
:DHCPAssociatedIP => 92,
|
125
|
-
:DHCPClientSystemArchType => 93,
|
126
|
-
:DHCPClientNetworkInterfaceIdent => 94,
|
127
|
-
:DHCPLDAP => 95,
|
128
|
-
# ??
|
129
|
-
:DHCPClientMachineIdent => 97,
|
130
|
-
:DHCPOGUA => 98,
|
131
|
-
# ??
|
132
|
-
:DHCPAutonomousSystemNumber => 109,
|
133
|
-
# ??
|
134
|
-
:DHCPNetInfoParentServerAddress => 112,
|
135
|
-
:DHCPNetInfoParentServerTag => 113,
|
136
|
-
:DHCPURL => 114,
|
137
|
-
:DHCPAutoConfigure => 116,
|
138
|
-
:DHCPNameServiceSearch => 117,
|
139
|
-
:DHCPSubnetSelection => 118,
|
140
|
-
:DHCPDNSDomainSearchList => 119,
|
141
|
-
:DHCPSIPServers => 120,
|
142
|
-
:DHCPClasslessStaticRoute => 121,
|
143
|
-
:DHCPCableLabsClientConfig => 122,
|
144
|
-
:DHCPGeoConf => 123,
|
145
|
-
# ??
|
146
|
-
:DHCPProxyAutoDiscovery => 252
|
147
|
-
}
|
148
|
-
|
149
|
-
OP_CONSTANTS_REV = {
|
150
31
|
0 => :Pad,
|
151
32
|
1 => :SubnetMask,
|
152
33
|
2 => :TimeOffset,
|
@@ -287,21 +168,21 @@ class Packet < Network::Protos::Base
|
|
287
168
|
bytes :dhcpoptions
|
288
169
|
|
289
170
|
def type
|
290
|
-
self.each_option( :MessageType ) do |
|
171
|
+
self.each_option( :MessageType ) do |_,data|
|
291
172
|
return OP_MESSAGETYPES[ data[0] ]
|
292
173
|
end
|
293
174
|
OP_MESSAGETYPES[ @op ]
|
294
175
|
end
|
295
176
|
|
296
177
|
def client_identifier
|
297
|
-
self.each_option( :ClientIdentifier ) do |
|
178
|
+
self.each_option( :ClientIdentifier ) do |_,data|
|
298
179
|
return data.pack('c*')
|
299
180
|
end
|
300
181
|
end
|
301
182
|
|
302
183
|
def authentication
|
303
184
|
# Thank you Wireshark BOOTP dissector!
|
304
|
-
self.each_option( :Authentication ) do |
|
185
|
+
self.each_option( :Authentication ) do |_,data|
|
305
186
|
auth = {}
|
306
187
|
|
307
188
|
auth['Protocol'] = AUTH_PROTOCOLS[ data[0] ]
|
@@ -333,8 +214,8 @@ class Packet < Network::Protos::Base
|
|
333
214
|
data = self.dhcpoptions[offset..offset+len-1]
|
334
215
|
offset += len
|
335
216
|
|
336
|
-
if sym.nil? or
|
337
|
-
yield(
|
217
|
+
if sym.nil? or OP_CONSTANTS[opt] == sym
|
218
|
+
yield( OP_CONSTANTS[opt], data )
|
338
219
|
end
|
339
220
|
end
|
340
221
|
end
|
@@ -58,7 +58,7 @@ class Target
|
|
58
58
|
@mac = Target.normalized_mac(mac) unless mac.nil?
|
59
59
|
@vendor = Target.lookup_vendor(@mac) unless mac.nil?
|
60
60
|
@hostname = nil
|
61
|
-
@resolver = Thread.new { resolve! } unless Context.get.options.no_target_nbns or @ip.nil?
|
61
|
+
@resolver = Thread.new { resolve! } unless Context.get.options.core.no_target_nbns or @ip.nil?
|
62
62
|
end
|
63
63
|
|
64
64
|
# Return the integer representation of the +ip+ attribute which can be
|
@@ -67,11 +67,16 @@ class Target
|
|
67
67
|
@ip.split('.').inject(0) {|total,value| (total << 8 ) + value.to_i}
|
68
68
|
end
|
69
69
|
|
70
|
+
# Return true if both the ip and mac are not nil.
|
71
|
+
def spoofable?
|
72
|
+
( !@ip.nil? and !@mac.nil? )
|
73
|
+
end
|
74
|
+
|
70
75
|
# +mac+ attribute setter, it will normalize the +value+ and perform
|
71
76
|
# a vendor lookup.
|
72
77
|
def mac=(value)
|
73
78
|
@mac = Target.normalized_mac(value)
|
74
|
-
@vendor = Target.lookup_vendor(@mac)
|
79
|
+
@vendor = Target.lookup_vendor(@mac) unless @mac.nil?
|
75
80
|
end
|
76
81
|
|
77
82
|
# Return a verbose string representation of this object.
|
@@ -0,0 +1,189 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
=begin
|
3
|
+
|
4
|
+
BETTERCAP
|
5
|
+
|
6
|
+
Author : Simone 'evilsocket' Margaritelli
|
7
|
+
Email : evilsocket@gmail.com
|
8
|
+
Blog : http://www.evilsocket.net/
|
9
|
+
|
10
|
+
This project is released under the GPL 3 license.
|
11
|
+
|
12
|
+
=end
|
13
|
+
|
14
|
+
module BetterCap
|
15
|
+
|
16
|
+
class CoreOptions
|
17
|
+
# Network interface.
|
18
|
+
attr_accessor :iface
|
19
|
+
# Gateway IP address.
|
20
|
+
attr_accessor :gateway
|
21
|
+
# Comma separated list of targets.
|
22
|
+
attr_accessor :targets
|
23
|
+
# Comma separated list of ip addresses to ignore.
|
24
|
+
attr_accessor :ignore
|
25
|
+
# If true will disable active network discovery, the program will just use
|
26
|
+
# the current ARP cache.
|
27
|
+
attr_accessor :arpcache
|
28
|
+
# If true, targets NBNS hostname resolution won't be performed.
|
29
|
+
attr_accessor :no_target_nbns
|
30
|
+
# Log file name.
|
31
|
+
attr_accessor :logfile
|
32
|
+
# If true the Logger will prepend timestamps to each line.
|
33
|
+
attr_accessor :log_timestamp
|
34
|
+
# If true will suppress every log message which is not an error or a warning.
|
35
|
+
attr_accessor :silent
|
36
|
+
# If true will enable debug messages.
|
37
|
+
attr_accessor :debug
|
38
|
+
# If different than 0, this time will be used as a delay while sending packets.
|
39
|
+
attr_accessor :packet_throttle
|
40
|
+
# If true, bettercap will check for updates then exit.
|
41
|
+
attr_accessor :check_updates
|
42
|
+
|
43
|
+
def initialize( iface )
|
44
|
+
@iface = iface
|
45
|
+
@gateway = nil
|
46
|
+
@targets = nil
|
47
|
+
@logfile = nil
|
48
|
+
@log_timestamp = false
|
49
|
+
@silent = false
|
50
|
+
@debug = false
|
51
|
+
@ignore = nil
|
52
|
+
@arpcache = false
|
53
|
+
@no_target_nbns = false
|
54
|
+
@packet_throttle = 0.0
|
55
|
+
@check_updates = false
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse!( ctx, opts )
|
59
|
+
opts.separator ""
|
60
|
+
opts.separator "MAIN:".bold
|
61
|
+
opts.separator ""
|
62
|
+
|
63
|
+
opts.on( '-I', '--interface IFACE', 'Network interface name - default: ' + @iface.to_s.yellow ) do |v|
|
64
|
+
@iface = v
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.on( '-G', '--gateway ADDRESS', 'Manually specify the gateway address, if not specified the current gateway will be retrieved and used. ' ) do |v|
|
68
|
+
@gateway = v
|
69
|
+
raise BetterCap::Error, "The specified gateway '#{v}' is not a valid IPv4 address." unless Network::Validator.is_ip?(v)
|
70
|
+
end
|
71
|
+
|
72
|
+
opts.on( '-T', '--target ADDRESS1,ADDRESS2', 'Target IP addresses, if not specified the whole subnet will be targeted.' ) do |v|
|
73
|
+
self.targets = v
|
74
|
+
end
|
75
|
+
|
76
|
+
opts.on( '--ignore ADDRESS1,ADDRESS2', 'Ignore these addresses if found while searching for targets.' ) do |v|
|
77
|
+
self.ignore = v
|
78
|
+
end
|
79
|
+
|
80
|
+
opts.on( '--no-discovery', "Do not actively search for hosts, just use the current ARP cache, default to #{'false'.yellow}." ) do
|
81
|
+
@arpcache = true
|
82
|
+
end
|
83
|
+
|
84
|
+
opts.on( '--no-target-nbns', 'Disable target NBNS hostname resolution.' ) do
|
85
|
+
@no_target_nbns = true
|
86
|
+
end
|
87
|
+
|
88
|
+
opts.on( '--packet-throttle NUMBER', 'Number of seconds ( can be a decimal number ) to wait between each packet to be sent.' ) do |v|
|
89
|
+
@packet_throttle = v.to_f
|
90
|
+
raise BetterCap::Error, "Invalid packet throttle value specified." if @packet_throttle <= 0.0
|
91
|
+
end
|
92
|
+
|
93
|
+
opts.on( '--check-updates', 'Will check if any update is available and then exit.' ) do
|
94
|
+
@check_updates = true
|
95
|
+
end
|
96
|
+
|
97
|
+
opts.on( '-h', '--help', 'Display the available options.') do
|
98
|
+
puts opts
|
99
|
+
puts "\nFor examples & docs please visit " + "http://bettercap.org/docs/".bold
|
100
|
+
exit
|
101
|
+
end
|
102
|
+
|
103
|
+
opts.separator ""
|
104
|
+
opts.separator "LOGGING:".bold
|
105
|
+
opts.separator ""
|
106
|
+
|
107
|
+
opts.on( '-O', '--log LOG_FILE', 'Log all messages into a file, if not specified the log messages will be only print into the shell.' ) do |v|
|
108
|
+
@logfile = v
|
109
|
+
end
|
110
|
+
|
111
|
+
opts.on( '--log-timestamp', 'Enable logging with timestamps for each line, disabled by default.' ) do
|
112
|
+
@log_timestamp = true
|
113
|
+
end
|
114
|
+
|
115
|
+
opts.on( '-D', '--debug', 'Enable debug logging.' ) do
|
116
|
+
@debug = true
|
117
|
+
end
|
118
|
+
|
119
|
+
opts.on( '--silent', "Suppress every message which is not an error or a warning, default to #{'false'.yellow}." ) do
|
120
|
+
@silent = true
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
def validate!
|
126
|
+
raise BetterCap::Error, 'This software must run as root.' unless Process.uid == 0
|
127
|
+
raise BetterCap::Error, 'No default interface found, please specify one with the -I argument.' if @iface.nil?
|
128
|
+
end
|
129
|
+
|
130
|
+
def discovery?
|
131
|
+
( @targets.nil? and !@arpcache )
|
132
|
+
end
|
133
|
+
|
134
|
+
# Split specified targets and parse them ( either as IP or MAC ), will raise a
|
135
|
+
# BetterCap::Error if one or more invalid addresses are specified.
|
136
|
+
def targets=(value)
|
137
|
+
@targets = []
|
138
|
+
|
139
|
+
value.split(",").each do |t|
|
140
|
+
if Network::Validator.is_ip?(t) or Network::Validator.is_mac?(t)
|
141
|
+
@targets << Network::Target.new(t)
|
142
|
+
|
143
|
+
elsif Network::Validator.is_range?(t)
|
144
|
+
Network::Validator.each_in_range( t ) do |address|
|
145
|
+
@targets << Network::Target.new(address)
|
146
|
+
end
|
147
|
+
|
148
|
+
elsif Network::Validator.is_netmask?(t)
|
149
|
+
Network::Validator.each_in_netmask(t) do |address|
|
150
|
+
@targets << Network::Target.new(address)
|
151
|
+
end
|
152
|
+
|
153
|
+
else
|
154
|
+
raise BetterCap::Error, "Invalid target specified '#{t}', valid formats are IP addresses, "\
|
155
|
+
"MAC addresses, IP ranges ( 192.168.1.1-30 ) or netmasks ( 192.168.1.1/24 ) ."
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Setter for the #ignore attribute, will raise a BetterCap::Error if one
|
161
|
+
# or more invalid IP addresses are specified.
|
162
|
+
def ignore=(value)
|
163
|
+
@ignore = value.split(",")
|
164
|
+
valid = @ignore.select { |target| Network::Validator.is_ip?(target) }
|
165
|
+
|
166
|
+
raise BetterCap::Error, "Invalid ignore addresses specified." if valid.empty?
|
167
|
+
|
168
|
+
invalid = @ignore - valid
|
169
|
+
invalid.each do |target|
|
170
|
+
Logger.warn "Not a valid address: #{target}"
|
171
|
+
end
|
172
|
+
|
173
|
+
@ignore = valid
|
174
|
+
|
175
|
+
Logger.warn "Ignoring #{valid.join(", ")} ."
|
176
|
+
end
|
177
|
+
|
178
|
+
# Return true if the +ip+ address needs to be ignored, otherwise false.
|
179
|
+
def ignore_ip?(ip)
|
180
|
+
!@ignore.nil? and @ignore.include?(ip)
|
181
|
+
end
|
182
|
+
|
183
|
+
# Return true if active host discovery is enabled, otherwise false.
|
184
|
+
def should_discover_hosts?
|
185
|
+
!@arpcache
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|