bettercap 1.1.8 → 1.1.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 851e88dcce552dfe264421c42fd1ad02c4ef0160
4
- data.tar.gz: 25e6d2a981d6113e86c150f833405c417594d613
3
+ metadata.gz: f3a44959da9a916d0c0c67da9eaf293547006ba4
4
+ data.tar.gz: 78e4dcf3c3da73095e0a291038de9f38928875bc
5
5
  SHA512:
6
- metadata.gz: 1d58eeb378e71ed4ef0059f5380763a4559d3c7f17d80da9ef54c415b760cfe47e38f52a9ea2cd2ba282ff326e87441c0b863790fa5b5b5b07ac0dd282246f3d
7
- data.tar.gz: d19bc791b7cedf8f64527a981f248dd9c5b35ce1c8937df7cf1878f97c1ca0c79722c91f7c914968e288a34c798c22b385d070daa9bea686861844a1904d4ab9
6
+ metadata.gz: 4f8fffb6c4c2c47d6e5fee83434a7f969f9201486a77a007d2f2a0d4486e5ade866421bbed71aa9373150ddb340b0b77567b462ac68987192d98f2b72bac2052
7
+ data.tar.gz: c312331cded4f9e729f0255860f66e6a1402ba29cfc4613dc8a2edca42e8bc263d1430e2aae3e4c99b69b5e1520abc02204b93b285232ec4177035c3e13a7408
data/TODO.md CHANGED
@@ -5,6 +5,8 @@ This is a list of TODOs I use to keep track of tasks and upcoming features.
5
5
  - [x] Implement `--ignore ADDR,ADDR,ADDR` option to filter out specific addresses from the targets list.
6
6
  - [x] HTTP 1.1 chunked response support.
7
7
  - [x] Ip address to hostname resolution.
8
+ - [ ] Wrap every class with `module BetterCap` and refactor old code.
9
+ - [ ] Use StreamLogger for both Proxy and Sniffer traffic.
8
10
  - [ ] Implement event-driven core plugin infrastructure ( for webui, etc ).
9
11
  - [ ] Implement web-ui core plugin.
10
12
  - [ ] Rewrite proxy class using [em-proxy](https://github.com/igrigorik/em-proxy) library.
data/bin/bettercap CHANGED
@@ -18,220 +18,51 @@ begin
18
18
  puts BetterCap::BANNER.green.bold
19
19
  puts "\n\n\n"
20
20
 
21
- ctx = Context.get
22
-
23
- OptionParser.new do |opts|
24
- opts.banner = "Usage: #{$0} [options]"
25
- opts.version = BetterCap::VERSION
26
-
27
- opts.on( '-G', '--gateway ADDRESS', 'Manually specify the gateway address, if not specified the current gateway will be retrieved and used. ' ) do |v|
28
- ctx.options.gateway = v
29
- end
30
-
31
- opts.on( '-I', '--interface IFACE', 'Network interface name - default: ' + ctx.options.iface.to_s ) do |v|
32
- ctx.options.iface = v
33
- end
34
-
35
- opts.on( '-S', '--spoofer NAME', 'Spoofer module to use, available: ' + SpooferFactory.available.join(', ') + ' - default: ' + ctx.options.spoofer ) do |v|
36
- ctx.options.spoofer = v
37
- end
38
-
39
- opts.on( '-T', '--target ADDRESS1,ADDRESS2', 'Target IP addresses, if not specified the whole subnet will be targeted.' ) do |v|
40
- ctx.options.target = v
41
- end
42
-
43
- opts.on( '--ignore ADDRESS1,ADDRESS2', 'Ignore these addresses if found while searching for targets.' ) do |v|
44
- ctx.options.ignore = v
45
- end
46
-
47
- 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|
48
- ctx.options.logfile = v
49
- end
50
-
51
- opts.on( '-D', '--debug', 'Enable debug logging.' ) do
52
- ctx.options.debug = true
53
- end
54
-
55
- opts.on( '-L', '--local', 'Parse packets coming from/to the address of this computer ( NOTE: Will set -X to true ), default to false.' ) do
56
- ctx.options.local = true
57
- ctx.options.sniffer = true
58
- end
59
-
60
- opts.on( '-X', '--sniffer', 'Enable sniffer.' ) do
61
- ctx.options.sniffer = true
62
- end
63
-
64
- opts.on( '--sniffer-source FILE', 'Load packets from the specified PCAP file instead of the interface ( will enable sniffer ).' ) do |v|
65
- ctx.options.sniffer = true
66
- ctx.options.sniffer_src = File.expand_path v
67
- end
68
-
69
- opts.on( '--sniffer-pcap FILE', 'Save all packets to the specified PCAP file ( will enable sniffer ).' ) do |v|
70
- ctx.options.sniffer = true
71
- ctx.options.sniffer_pcap = File.expand_path v
72
- end
73
-
74
- opts.on( '--sniffer-filter EXPRESSION', 'Configure the sniffer to use this BPF filter ( will enable sniffer ).' ) do |v|
75
- ctx.options.sniffer = true
76
- ctx.options.sniffer_filter = v
77
- end
78
-
79
- opts.on( '-P', '--parsers PARSERS', 'Comma separated list of packet parsers to enable, "*" for all ( NOTE: Will set -X to true ), available: ' + ParserFactory.available.join(', ') + ' - default: *' ) do |v|
80
- ctx.options.sniffer = true
81
- ctx.options.parsers = ParserFactory.from_cmdline(v)
82
- end
83
-
84
- opts.on( '--no-discovery', 'Do not actively search for hosts, just use the current ARP cache, default to false.' ) do
85
- ctx.options.arpcache = true
86
- end
87
-
88
- opts.on( '--no-spoofing', 'Disable spoofing, alias for --spoofer NONE.' ) do
89
- ctx.options.spoofer = 'NONE'
90
- end
91
-
92
- opts.on( '--half-duplex', 'Enable half-duplex MITM, this will make bettercap work in those cases when the router is not vulnerable.' ) do
93
- ctx.options.half_duplex = true
94
- end
95
-
96
- opts.on( '--proxy', 'Enable HTTP proxy and redirects all HTTP requests to it, default to false.' ) do
97
- ctx.options.proxy = true
98
- end
99
-
100
- opts.on( '--proxy-https', 'Enable HTTPS proxy and redirects all HTTPS requests to it, default to false.' ) do
101
- ctx.options.proxy = true
102
- ctx.options.proxy_https = true
103
- end
104
-
105
- opts.on( '--proxy-port PORT', 'Set HTTP proxy port, default to ' + ctx.options.proxy_port.to_s + ' .' ) do |v|
106
- ctx.options.proxy = true
107
- ctx.options.proxy_port = v.to_i
108
- end
109
-
110
- opts.on( '--proxy-https-port PORT', 'Set HTTPS proxy port, default to ' + ctx.options.proxy_https_port.to_s + ' .' ) do |v|
111
- ctx.options.proxy = true
112
- ctx.options.proxy_https = true
113
- ctx.options.proxy_https_port = v.to_i
114
- end
115
-
116
- opts.on( '--proxy-pem FILE', 'Use a custom PEM certificate file for the HTTPS proxy.' ) do |v|
117
- ctx.options.proxy = true
118
- ctx.options.proxy_https = true
119
- ctx.options.proxy_pem_file = File.expand_path v
120
- end
121
-
122
- opts.on( '--proxy-module MODULE', 'Ruby proxy module to load.' ) do |v|
123
- ctx.options.proxy = true
124
- ctx.options.proxy_module = File.expand_path v
125
- end
126
-
127
- opts.on( '--custom-proxy ADDRESS', 'Use a custom HTTP upstream proxy instead of the builtin one.' ) do |v|
128
- ctx.options.custom_proxy = v
129
- end
130
-
131
- opts.on( '--custom-proxy-port PORT', 'Specify a port for the custom HTTP upstream proxy, default to ' + ctx.options.custom_proxy_port.to_s + ' .' ) do |v|
132
- ctx.options.custom_proxy_port = v.to_i
133
- end
134
-
135
- opts.on( '--custom-https-proxy ADDRESS', 'Use a custom HTTPS upstream proxy instead of the builtin one.' ) do |v|
136
- ctx.options.custom_https_proxy = v
137
- end
138
-
139
- opts.on( '--custom-https-proxy-port PORT', 'Specify a port for the custom HTTPS upstream proxy, default to ' + ctx.options.custom_https_proxy_port.to_s + ' .' ) do |v|
140
- ctx.options.custom_https_proxy_port = v.to_i
141
- end
142
-
143
- opts.on( '--httpd', 'Enable HTTP server, default to false.' ) do
144
- ctx.options.httpd = true
145
- end
146
-
147
- opts.on( '--httpd-port PORT', 'Set HTTP server port, default to ' + ctx.options.httpd_port.to_s + '.' ) do |v|
148
- ctx.options.httpd = true
149
- ctx.options.httpd_port = v.to_i
150
- end
151
-
152
- opts.on( '--httpd-path PATH', 'Set HTTP server path, default to ' + ctx.options.httpd_path + '.' ) do |v|
153
- ctx.options.httpd = true
154
- ctx.options.httpd_path = v
155
- end
156
-
157
- opts.on( '--check-updates', 'Will check if any update is available and then exit.' ) do
158
- ctx.options.check_updates = true
159
- end
160
-
161
- opts.on('-h', '--help', 'Display the available options.') do
162
- puts opts
163
- puts "\nFor examples & docs please visit " + "http://bettercap.org/docs/".bold
164
- exit
165
- end
166
- end.parse!
167
-
168
- if ctx.options.check_updates
169
- error_policy = lambda { |e|
170
- Logger.error("Could not check for udpates: #{e.message}")
171
- }
172
-
173
- ctx.check_updates(error_policy)
174
- exit
175
- end
176
-
177
- raise BetterCap::Error, 'This software must run as root.' unless Process.uid == 0
178
- raise BetterCap::Error, 'No default interface found, please specify one with the -I argument.' unless !ctx.options.iface.nil?
179
-
180
- Logger.debug_enabled = true unless !ctx.options.debug
181
-
182
- Logger.logfile = ctx.options.logfile
183
-
184
-
185
- unless ctx.options.gateway.nil?
186
- raise BetterCap::Error, "Invalid gateway" if !Network.is_ip?(ctx.options.gateway)
187
- ctx.gateway = ctx.options.gateway
188
- Logger.info("Targetting manual gateway #{ctx.gateway}")
189
- end
190
-
191
- ctx.update_network
21
+ # Create global context, parse command line arguments and perform basic
22
+ # error checking.
23
+ ctx = Options.parse!
192
24
 
25
+ # Start targets auto discovery if needed.
193
26
  if ctx.options.target.nil?
194
- Logger.info( "Targeting the whole subnet #{ctx.network.to_range} ..." ) unless ctx.options.has_spoofer?
195
-
196
- ctx.start_discovery_thread
197
- else
198
- ctx.targets = ctx.options.to_targets
27
+ Logger.info( "Targeting the whole subnet #{ctx.ifconfig[:ip4_obj].to_range} ..." ) unless ctx.options.has_spoofer?
28
+ ctx.discovery.start
199
29
  end
200
30
 
201
- ctx.spoofer = ctx.options.to_spoofers
31
+ # Start network spoofers if any.
202
32
  ctx.spoofer.each do |spoofer|
203
33
  spoofer.start
204
34
  end
205
35
 
36
+ # Start proxies and setup port redirection.
206
37
  if ctx.options.proxy
207
38
  if ctx.options.has_http_sniffer_enabled?
208
39
  Logger.warn "WARNING: Both HTTP transparent proxy and URL parser are enabled, you're gonna see duplicated logs."
209
40
  end
210
-
211
41
  ctx.create_proxies
212
42
  end
213
43
 
214
- ctx.enable_port_redirection
44
+ ctx.enable_port_redirection!
215
45
 
46
+ # Start local HTTP server.
216
47
  if ctx.options.httpd
217
48
  ctx.httpd = HTTPD::Server.new( ctx.options.httpd_port, ctx.options.httpd_path )
218
49
  ctx.httpd.start
219
50
  end
220
51
 
52
+ # Start network sniffer.
221
53
  if ctx.options.sniffer
222
54
  Sniffer.start ctx
223
55
  else
224
- unless ctx.options.has_spoofer?
225
- Logger.warn 'WARNING: Sniffer module was NOT enabled ( -X argument ), this will cause the MITM to run but no data to be collected.'
226
- end
56
+ Logger.warn 'WARNING: Sniffer module was NOT enabled ( -X argument ), this '\
57
+ 'will cause the MITM to run but no data to be collected.' unless ctx.options.has_spoofer?
58
+ end
227
59
 
228
- loop do
229
- sleep 1
230
- end
60
+ loop do
61
+ sleep 10
231
62
  end
232
63
 
233
64
  rescue SystemExit, Interrupt
234
- Logger.write "\n"
65
+ Logger.raw "\n"
235
66
 
236
67
  rescue BetterCap::Error => e
237
68
  Logger.error e.message
data/lib/bettercap.rb CHANGED
@@ -24,8 +24,10 @@ require 'ipaddr'
24
24
  Object.send :remove_const, :Config rescue nil
25
25
  Config = RbConfig
26
26
 
27
+ require 'bettercap/update_checker'
27
28
  require 'bettercap/error'
28
29
  require 'bettercap/options'
30
+ require 'bettercap/discovery'
29
31
  require 'bettercap/context'
30
32
  require 'bettercap/monkey/packetfu/utils'
31
33
  require 'bettercap/factories/firewall_factory'
@@ -22,11 +22,11 @@ class IFirewall
22
22
  not_implemented_method!
23
23
  end
24
24
 
25
- def add_port_redirection( iface, proto, from, addr, to )
25
+ def add_port_redirection( r )
26
26
  not_implemented_method!
27
27
  end
28
28
 
29
- def del_port_redirection( iface, proto, from, addr, to )
29
+ def del_port_redirection( r )
30
30
  not_implemented_method!
31
31
  end
32
32
 
@@ -11,15 +11,12 @@ This project is released under the GPL 3 license.
11
11
  =end
12
12
 
13
13
  # this class holds global states & data
14
- require 'bettercap/version'
15
14
  require 'bettercap/error'
16
- require 'net/http'
17
- require 'json'
18
15
 
19
16
  class Context
20
- attr_accessor :options, :ifconfig, :network, :firewall, :gateway,
21
- :targets, :spoofer, :httpd,
22
- :certificate
17
+ attr_accessor :options, :ifconfig, :firewall, :gateway,
18
+ :targets, :discovery, :spoofer, :httpd,
19
+ :certificate, :running
23
20
 
24
21
  @@instance = nil
25
22
 
@@ -35,135 +32,53 @@ class Context
35
32
  Logger.debug e.message
36
33
  end
37
34
 
38
- @options = Options.new iface
39
- @ifconfig = nil
40
- @network = nil
41
- @firewall = nil
42
- @gateway = nil
43
- @targets = []
44
- @proxy_processor = nil
45
- @spoofer = nil
46
- @httpd = nil
47
- @certificate = nil
48
- @proxies = []
49
- @redirections = []
50
- @discovery_running = false
51
- @discovery_thread = nil
35
+ @running = true
36
+ @options = Options.new iface
37
+ @ifconfig = nil
38
+ @firewall = nil
39
+ @gateway = nil
40
+ @targets = []
41
+ @proxy_processor = nil
42
+ @spoofer = nil
43
+ @httpd = nil
44
+ @certificate = nil
45
+ @proxies = []
46
+ @redirections = []
47
+ @discovery = Discovery.new self
48
+ @firewall = FirewallFactory.get_firewall
52
49
  end
53
50
 
54
- def check_updates(error_policy = ->{ raise })
55
- ver = get_latest_version
56
-
57
- case ver
58
- when BetterCap::VERSION
59
- Logger.info 'You are running the latest version.'
60
- else
61
- Logger.warn "New version '#{ver}' available!"
62
- end
63
- rescue Exception => e
64
- error_policy.call(e)
65
- end
66
-
67
- def get_latest_version
68
- Logger.info 'Checking for updates ...'
69
-
70
- api = URI('https://rubygems.org/api/v1/versions/bettercap/latest.json')
71
- response = Net::HTTP.get_response(api)
72
-
73
- case response
74
- when Net::HTTPSuccess
75
- json = JSON.parse(response.body)
76
- else
77
- raise response.message
78
- end
79
-
80
- return json['version']
81
- end
82
-
83
- def update_network
84
- @firewall = FirewallFactory.get_firewall
51
+ def update!
85
52
  @ifconfig = PacketFu::Utils.ifconfig @options.iface
86
- @network = @ifconfig[:ip4_obj]
87
53
  @gateway = Network.get_gateway if @gateway.nil?
88
54
 
89
- raise BetterCap::Error, "Could not determine IPv4 address of '#{@options.iface}' interface." unless !@network.nil?
55
+ raise BetterCap::Error, "Could not determine IPv4 address of '#{@options.iface}', make sure this interface "\
56
+ 'is active and connected.' if @ifconfig[:ip4_obj].nil?
57
+
58
+ raise BetterCap::Error, "Could not detect the gateway address for interface #{@options.iface}, "\
59
+ 'make sure you\'ve specified the correct network interface to use and to have the '\
60
+ 'correct network configuration, this could also happen if bettercap '\
61
+ 'is launched from a virtual environment.' if @gateway.nil? or !Network.is_ip?(@gateway)
90
62
 
91
- Logger.debug "network=#{@network} gateway=#{@gateway} local_ip=#{@ifconfig[:ip_saddr]}"
63
+ Logger.debug "network=#{@ifconfig[:ip4_obj]} gateway=#{@gateway} local_ip=#{@ifconfig[:ip_saddr]}"
92
64
  Logger.debug "IFCONFIG: #{@ifconfig.inspect}"
93
65
  end
94
66
 
95
67
  def find_target ip, mac
96
68
  @targets.each do |target|
97
- if target.ip == ip && ( mac.nil? || target.mac == mac )
69
+ if target.equals?(ip,mac)
98
70
  return target
99
71
  end
100
72
  end
101
73
  nil
102
74
  end
103
75
 
104
- def start_discovery_thread
105
- @discovery_running = true
106
- @discovery_thread = Thread.new {
107
- Logger.info( 'Network discovery thread started.' ) unless @options.arpcache
108
-
109
- while @discovery_running
110
- empty_list = false
111
-
112
- if @targets.empty? and @options.should_discover_hosts?
113
- empty_list = true
114
- Logger.info 'Searching for alive targets ...'
115
- else
116
- # make sure we don't stress the logging system
117
- 10.times do
118
- sleep 1
119
- if !@discovery_running
120
- break
121
- end
122
- end
123
- end
124
-
125
- @targets = Network.get_alive_targets self
126
-
127
- if empty_list and @options.should_discover_hosts?
128
- Logger.info "Collected #{@targets.size} total targets."
129
- @targets.each do |target|
130
- Logger.info " #{target}"
131
- end
132
- end
133
- end
134
- }
135
- end
136
-
137
- def stop_discovery_thread
138
- @discovery_running = false
139
-
140
- if @discovery_thread != nil
141
- Logger.info( 'Stopping network discovery thread ...' ) unless @options.arpcache
142
-
143
- begin
144
- @discovery_thread.exit
145
- rescue
146
- end
147
- end
148
- end
149
-
150
- def enable_port_redirection
76
+ def enable_port_redirection!
151
77
  @redirections = @options.to_redirections @ifconfig
152
78
  @redirections.each do |r|
153
79
  Logger.warn "Redirecting #{r.protocol} traffic from port #{r.src_port} to #{r.dst_address}:#{r.dst_port}"
154
-
155
- @firewall.add_port_redirection( r.interface, r.protocol, r.src_port, r.dst_address, r.dst_port )
156
- end
157
- end
158
-
159
- def disable_port_redirection
160
- @redirections.each do |r|
161
- Logger.debug "Removing #{r.protocol} port redirect from port #{r.src_port} to #{r.dst_address}:#{r.dst_port}"
162
-
163
- @firewall.del_port_redirection( r.interface, r.protocol, r.src_port, r.dst_address, r.dst_port )
80
+ @firewall.add_port_redirection( r )
164
81
  end
165
-
166
- @redirections = []
167
82
  end
168
83
 
169
84
  def create_proxies
@@ -220,26 +135,31 @@ class Context
220
135
  end
221
136
 
222
137
  def finalize
223
- stop_discovery_thread
138
+ @running = false
224
139
 
225
- if !@spoofer.nil? and @spoofer.length != 0
226
- @spoofer.each do |itr|
227
- itr.stop
228
- end
140
+ Logger.info 'Shutting down, hang on ...'
141
+
142
+ Logger.debug 'Stopping target discovery manager ...'
143
+ @discovery.stop
144
+
145
+ Logger.debug 'Stopping spoofers ...'
146
+ @spoofer.each do |spoofer|
147
+ spoofer.stop
229
148
  end
230
149
 
150
+ Logger.debug 'Stopping proxies ...'
231
151
  @proxies.each do |proxy|
232
152
  proxy.stop
233
153
  end
234
154
 
235
- disable_port_redirection
236
-
237
- if !@firewall.nil?
238
- @firewall.restore
155
+ Logger.debug 'Disabling port redirections ...'
156
+ @redirections.each do |r|
157
+ @firewall.del_port_redirection( r )
239
158
  end
240
159
 
241
- if !@httpd.nil?
242
- @httpd.stop
243
- end
160
+ Logger.debug 'Restoring firewall state ...'
161
+ @firewall.restore
162
+
163
+ @httpd.stop unless @httpd.nil?
244
164
  end
245
165
  end