bettercap 1.4.6 → 1.5.0
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/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
|