bettercap 1.1.8 → 1.1.9

Sign up to get free protection for your applications and to get access to all the features.
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