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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/bin/bettercap +1 -1
  3. data/lib/bettercap.rb +1 -0
  4. data/lib/bettercap/context.rb +63 -70
  5. data/lib/bettercap/discovery/agents/base.rb +2 -2
  6. data/lib/bettercap/discovery/thread.rb +5 -4
  7. data/lib/bettercap/firewalls/base.rb +2 -4
  8. data/lib/bettercap/firewalls/{osx.rb → bsd.rb} +3 -3
  9. data/lib/bettercap/firewalls/linux.rb +2 -2
  10. data/lib/bettercap/firewalls/redirection.rb +5 -2
  11. data/lib/bettercap/logger.rb +6 -11
  12. data/lib/bettercap/memory.rb +56 -0
  13. data/lib/bettercap/monkey/em-proxy/proxy.rb +23 -0
  14. data/lib/bettercap/monkey/packetfu/pcap.rb +51 -0
  15. data/lib/bettercap/network/arp_reader.rb +2 -2
  16. data/lib/bettercap/network/network.rb +2 -2
  17. data/lib/bettercap/network/packet_queue.rb +2 -2
  18. data/lib/bettercap/network/protos/base.rb +8 -5
  19. data/lib/bettercap/network/protos/dhcp.rb +5 -124
  20. data/lib/bettercap/network/target.rb +7 -2
  21. data/lib/bettercap/options/core_options.rb +189 -0
  22. data/lib/bettercap/options/options.rb +167 -0
  23. data/lib/bettercap/options/proxy_options.rb +258 -0
  24. data/lib/bettercap/options/server_options.rb +71 -0
  25. data/lib/bettercap/options/sniff_options.rb +90 -0
  26. data/lib/bettercap/options/spoof_options.rb +71 -0
  27. data/lib/bettercap/proxy/{module.rb → http/module.rb} +8 -4
  28. data/lib/bettercap/proxy/{modules → http/modules}/injectcss.rb +2 -2
  29. data/lib/bettercap/proxy/{modules → http/modules}/injecthtml.rb +2 -2
  30. data/lib/bettercap/proxy/{modules → http/modules}/injectjs.rb +2 -2
  31. data/lib/bettercap/proxy/{proxy.rb → http/proxy.rb} +5 -2
  32. data/lib/bettercap/proxy/{request.rb → http/request.rb} +4 -0
  33. data/lib/bettercap/proxy/{response.rb → http/response.rb} +3 -0
  34. data/lib/bettercap/proxy/{ssl → http/ssl}/authority.rb +3 -1
  35. data/lib/bettercap/proxy/{ssl → http/ssl}/bettercap-ca.pem +0 -0
  36. data/lib/bettercap/proxy/{ssl → http/ssl}/server.rb +3 -1
  37. data/lib/bettercap/proxy/{sslstrip → http/sslstrip}/cookiemonitor.rb +2 -0
  38. data/lib/bettercap/proxy/{sslstrip → http/sslstrip}/lock.ico +0 -0
  39. data/lib/bettercap/proxy/{sslstrip → http/sslstrip}/strip.rb +4 -2
  40. data/lib/bettercap/proxy/{streamer.rb → http/streamer.rb} +7 -4
  41. data/lib/bettercap/proxy/stream_logger.rb +25 -9
  42. data/lib/bettercap/proxy/tcp/module.rb +75 -0
  43. data/lib/bettercap/proxy/tcp/proxy.rb +123 -0
  44. data/lib/bettercap/proxy/thread_pool.rb +1 -1
  45. data/lib/bettercap/sniffer/parsers/post.rb +1 -1
  46. data/lib/bettercap/sniffer/parsers/url.rb +1 -1
  47. data/lib/bettercap/sniffer/sniffer.rb +23 -17
  48. data/lib/bettercap/spoofers/arp.rb +21 -9
  49. data/lib/bettercap/spoofers/base.rb +12 -16
  50. data/lib/bettercap/spoofers/icmp.rb +4 -5
  51. data/lib/bettercap/spoofers/none.rb +0 -1
  52. data/lib/bettercap/version.rb +1 -1
  53. metadata +48 -19
  54. data/lib/bettercap/firewalls/openbsd.rb +0 -77
  55. data/lib/bettercap/options.rb +0 -600
@@ -0,0 +1,90 @@
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 SniffOptions
17
+ # If true the BetterCap::Sniffer will be enabled.
18
+ attr_accessor :enabled
19
+ # PCAP file name to save captured packets to.
20
+ attr_accessor :output
21
+ # BPF filter to apply to sniffed packets.
22
+ attr_accessor :filter
23
+ # Input PCAP file, if specified the BetterCap::Sniffer will read packets
24
+ # from it instead of the network.
25
+ attr_accessor :src
26
+ # Comma separated list of BetterCap::Parsers to enable.
27
+ attr_accessor :parsers
28
+ # Regular expression to use with the BetterCap::Parsers::Custom parser.
29
+ attr_accessor :custom_parser
30
+ # If true, bettercap will sniff packets from the local interface as well.
31
+ attr_accessor :local
32
+
33
+ def initialize
34
+ @enabled = false
35
+ @output = nil
36
+ @filter = nil
37
+ @src = nil
38
+ @parsers = ['*']
39
+ @custom_parser = nil
40
+ @local = false
41
+ end
42
+
43
+ def parse!( ctx, opts )
44
+ opts.separator ""
45
+ opts.separator "SNIFFING:".bold
46
+ opts.separator ""
47
+
48
+ opts.on( '-X', '--sniffer', 'Enable sniffer.' ) do
49
+ @enabled = true
50
+ end
51
+
52
+ opts.on( '-L', '--local', "Parse packets coming from/to the address of this computer ( NOTE: Will set -X to true ), default to #{'false'.yellow}." ) do
53
+ @enabled = true
54
+ @local = true
55
+ end
56
+
57
+ opts.on( '--sniffer-source FILE', 'Load packets from the specified PCAP file instead of the interface ( will enable sniffer ).' ) do |v|
58
+ @enabled = true
59
+ @src = File.expand_path v
60
+ end
61
+
62
+ opts.on( '--sniffer-output FILE', 'Save all packets to the specified PCAP file ( will enable sniffer ).' ) do |v|
63
+ @enabled = true
64
+ @output = File.expand_path v
65
+ end
66
+
67
+ opts.on( '--sniffer-filter EXPRESSION', 'Configure the sniffer to use this BPF filter ( will enable sniffer ).' ) do |v|
68
+ @enabled = true
69
+ @filter = v
70
+ end
71
+
72
+ opts.on( '-P', '--parsers PARSERS', "Comma separated list of packet parsers to enable, '*' for all ( NOTE: Will set -X to true ), available: #{Parsers::Base.available.map { |x| x.yellow }.join(', ')} - default: #{'*'.yellow}" ) do |v|
73
+ @enabled = true
74
+ @parsers = Parsers::Base.from_cmdline(v)
75
+ end
76
+
77
+ opts.on( '--custom-parser EXPRESSION', 'Use a custom regular expression in order to capture and show sniffed data ( NOTE: Will set -X to true ).' ) do |v|
78
+ @enabled = true
79
+ @parsers = ['CUSTOM']
80
+ @custom_parser = Regexp.new(v)
81
+ end
82
+ end
83
+
84
+ # Return true if the specified +parser+ is enabled, otherwise false.
85
+ def enabled?( parser = nil )
86
+ @enabled and ( parser.nil? or ( @parsers.include?('*') or @parsers.include?(parser.upcase) ) )
87
+ end
88
+ end
89
+
90
+ end
@@ -0,0 +1,71 @@
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 SpoofOptions
17
+ # Name of the spoofer to use.
18
+ attr_accessor :spoofer
19
+ # If true half duplex mode is enabled.
20
+ attr_accessor :half_duplex
21
+ # If true, bettercap won't forward packets for any target, causing
22
+ # connections to be killed.
23
+ attr_accessor :kill
24
+
25
+ def initialize
26
+ @spoofer = 'ARP'
27
+ @half_duplex = false
28
+ @kill = false
29
+ end
30
+
31
+ def parse!( ctx, opts )
32
+ opts.separator ""
33
+ opts.separator "SPOOFING:".bold
34
+ opts.separator ""
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|
37
+ @spoofer = v
38
+ end
39
+
40
+ opts.on( '--no-spoofing', "Disable spoofing, alias for #{'--spoofer NONE'.yellow}." ) do
41
+ @spoofer = 'NONE'
42
+ end
43
+
44
+ opts.on( '--half-duplex', 'Enable half-duplex MITM, this will make bettercap work in those cases when the router is not vulnerable.' ) do
45
+ @half_duplex = true
46
+ end
47
+
48
+ opts.on( '--kill', 'Instead of forwarding packets, this switch will make targets connections to be killed.' ) do
49
+ @kill = true
50
+ end
51
+ end
52
+
53
+ # Return true if a spoofer module was specified, otherwise false.
54
+ def enabled?
55
+ @spoofer.upcase != 'NONE'
56
+ end
57
+
58
+
59
+ # Parse spoofers and return a list of BetterCap::Spoofers objects. Raise a
60
+ # BetterCap::Error if an invalid spoofer name was specified.
61
+ def parse_spoofers
62
+ valid = []
63
+ @spoofer.split(",").each do |module_name|
64
+ valid << Spoofers::Base.get_by_name( module_name )
65
+ end
66
+ valid
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -13,6 +13,8 @@ This project is released under the GPL 3 license.
13
13
 
14
14
  module BetterCap
15
15
  module Proxy
16
+ module HTTP
17
+
16
18
  # Base class for transparent proxy modules.
17
19
  class Module
18
20
  @@path = File.dirname(__FILE__) + '/modules/'
@@ -40,13 +42,13 @@ class Module
40
42
  # Load the module with +name+.
41
43
  def self.load(ctx, opts, name)
42
44
  if self.is_builtin?(name)
43
- ctx.options.proxy_module = "#{@@path}/#{name}.rb"
45
+ ctx.options.proxies.proxy_module = "#{@@path}/#{name}.rb"
44
46
  else
45
- ctx.options.proxy_module = File.expand_path(name)
47
+ ctx.options.proxies.proxy_module = File.expand_path(name)
46
48
  end
47
49
 
48
50
  begin
49
- require ctx.options.proxy_module
51
+ require ctx.options.proxies.proxy_module
50
52
 
51
53
  self.register_options(opts)
52
54
  rescue LoadError
@@ -83,7 +85,7 @@ class Module
83
85
 
84
86
  private
85
87
 
86
- # Loop each available BetterCap::Proxy::Proxy module and yield each
88
+ # Loop each available BetterCap::Proxy::HTTP::Proxy module and yield each
87
89
  # one of them for the given code block.
88
90
  def self.each_module
89
91
  old_verbose, $VERBOSE = $VERBOSE, nil
@@ -97,5 +99,7 @@ class Module
97
99
  $VERBOSE = old_verbose
98
100
  end
99
101
  end
102
+
103
+ end
100
104
  end
101
105
  end
@@ -12,7 +12,7 @@ This project is released under the GPL 3 license.
12
12
  =end
13
13
 
14
14
  # This proxy module will take care of CSS code injection.
15
- class InjectCSS < BetterCap::Proxy::Module
15
+ class InjectCSS < BetterCap::Proxy::HTTP::Module
16
16
  # CSS data to be injected.
17
17
  @@cssdata = nil
18
18
  # CSS file URL to be injected.
@@ -51,7 +51,7 @@ class InjectCSS < BetterCap::Proxy::Module
51
51
  raise BetterCap::Error, "No --css-file, --css-url or --css-data options specified for the proxy module." if @@cssdata.nil? and @@cssurl.nil?
52
52
  end
53
53
 
54
- # Called by the BetterCap::Proxy::Proxy processor on each HTTP +request+ and
54
+ # Called by the BetterCap::Proxy::HTTP::Proxy processor on each HTTP +request+ and
55
55
  # +response+.
56
56
  def on_request( request, response )
57
57
  # is it a html page?
@@ -12,7 +12,7 @@ This project is released under the GPL 3 license.
12
12
  =end
13
13
 
14
14
  # This proxy module will take care of HTML code injection.
15
- class InjectHTML < BetterCap::Proxy::Module
15
+ class InjectHTML < BetterCap::Proxy::HTTP::Module
16
16
  # URL of the iframe if --html-iframe-url was specified.
17
17
  @@iframe = nil
18
18
  # HTML data to be injected.
@@ -39,7 +39,7 @@ class InjectHTML < BetterCap::Proxy::Module
39
39
  raise BetterCap::Error, "No --html-data or --html-iframe-url options specified for the proxy module." if @@data.nil? and @@iframe.nil?
40
40
  end
41
41
 
42
- # Called by the BetterCap::Proxy::Proxy processor on each HTTP +request+ and
42
+ # Called by the BetterCap::Proxy::HTTP::Proxy processor on each HTTP +request+ and
43
43
  # +response+.
44
44
  def on_request( request, response )
45
45
  # is it a html page?
@@ -12,7 +12,7 @@ This project is released under the GPL 3 license.
12
12
  =end
13
13
 
14
14
  # This proxy module will take care of Javascript code injection.
15
- class InjectJS < BetterCap::Proxy::Module
15
+ class InjectJS < BetterCap::Proxy::HTTP::Module
16
16
  # JS data to be injected.
17
17
  @@jsdata = nil
18
18
  # JS file URL to be injected.
@@ -51,7 +51,7 @@ class InjectJS < BetterCap::Proxy::Module
51
51
  raise BetterCap::Error, "No --js-file, --js-url or --js-data options specified for the proxy module." if @@jsdata.nil? and @@jsurl.nil?
52
52
  end
53
53
 
54
- # Called by the BetterCap::Proxy::Proxy processor on each HTTP +request+ and
54
+ # Called by the BetterCap::Proxy::HTTP::Proxy processor on each HTTP +request+ and
55
55
  # +response+.
56
56
  def on_request( request, response )
57
57
  # is it a html page?
@@ -13,7 +13,9 @@ This project is released under the GPL 3 license.
13
13
 
14
14
  module BetterCap
15
15
  module Proxy
16
- # Transparent proxy class.
16
+ module HTTP
17
+
18
+ # Transparent HTTP proxy class.
17
19
  class Proxy
18
20
  # Initialize the transparent proxy, making it listen on +address+:+port+.
19
21
  # If +is_https+ is true a HTTPS proxy will be created, otherwise a HTTP one.
@@ -171,9 +173,10 @@ class Proxy
171
173
 
172
174
  # Return true if sslstrip is needed for this proxy instance.
173
175
  def need_sslstrip?
174
- ( Context.get.options.sslstrip and !@is_https )
176
+ ( Context.get.options.proxies.sslstrip and !@is_https )
175
177
  end
176
178
  end
177
179
 
178
180
  end
179
181
  end
182
+ end
@@ -13,6 +13,8 @@ This project is released under the GPL 3 license.
13
13
 
14
14
  module BetterCap
15
15
  module Proxy
16
+ module HTTP
17
+
16
18
  # HTTP request parser.
17
19
  class Request
18
20
  # HTTP method.
@@ -184,5 +186,7 @@ class Request
184
186
  @host = value if name == 'Host'
185
187
  end
186
188
  end
189
+
190
+ end
187
191
  end
188
192
  end
@@ -13,6 +13,8 @@ This project is released under the GPL 3 license.
13
13
 
14
14
  module BetterCap
15
15
  module Proxy
16
+ module HTTP
17
+
16
18
  # HTTP response parser.
17
19
  class Response
18
20
  # HTTP protocol version
@@ -221,3 +223,4 @@ end
221
223
 
222
224
  end
223
225
  end
226
+ end
@@ -13,6 +13,7 @@ This project is released under the GPL 3 license.
13
13
 
14
14
  module BetterCap
15
15
  module Proxy
16
+ module HTTP
16
17
  module SSL
17
18
 
18
19
  # Simple wrapper class used to fetch a server HTTPS certificate.
@@ -67,7 +68,7 @@ class Store
67
68
  s_cert = Fetcher.fetch( hostname, port )
68
69
  save_to_file( s_cert, filename )
69
70
  else
70
- Logger.info "[#{'SSL'.green}] Loaded HTTPS certificate for '#{hostname}' from store."
71
+ Logger.debug "[#{'SSL'.green}] Loaded HTTPS certificate for '#{hostname}' from store."
71
72
  end
72
73
 
73
74
  @store[key] = s_cert
@@ -174,3 +175,4 @@ end
174
175
  end
175
176
  end
176
177
  end
178
+ end
@@ -13,6 +13,7 @@ This project is released under the GPL 3 license.
13
13
 
14
14
  module BetterCap
15
15
  module Proxy
16
+ module HTTP
16
17
  module SSL
17
18
 
18
19
  # Little utility class to handle SSLServer creation.
@@ -26,7 +27,7 @@ class Server
26
27
 
27
28
  # Create an instance from the TCPSocket +socket+.
28
29
  def initialize( socket )
29
- @authority = Authority.new( Context.get.options.proxy_pem_file )
30
+ @authority = Authority.new( Context.get.options.proxies.proxy_pem_file )
30
31
  @context = OpenSSL::SSL::SSLContext.new
31
32
  @context.cert = @authority.certificate
32
33
  @context.key = @authority.key
@@ -59,3 +60,4 @@ end
59
60
  end
60
61
  end
61
62
  end
63
+ end
@@ -13,6 +13,7 @@ This project is released under the GPL 3 license.
13
13
 
14
14
  module BetterCap
15
15
  module Proxy
16
+ module HTTP
16
17
  module SSLStrip
17
18
 
18
19
  # Class to handle a cookies for sslstrip.
@@ -63,3 +64,4 @@ end
63
64
  end
64
65
  end
65
66
  end
67
+ end
@@ -13,6 +13,7 @@ This project is released under the GPL 3 license.
13
13
 
14
14
  module BetterCap
15
15
  module Proxy
16
+ module HTTP
16
17
  module SSLStrip
17
18
 
18
19
  # Represent a stripped url associated to the client that requested it.
@@ -105,7 +106,7 @@ class Strip
105
106
  @stripped = []
106
107
  @cookies = CookieMonitor.new
107
108
  @favicon = Response.from_file( File.dirname(__FILE__) + '/lock.ico', 'image/x-icon' )
108
- @resolver = BetterCap::Network::Servers::DNSD.new( nil, ctx.ifconfig[:ip_saddr], ctx.options.dnsd_port )
109
+ @resolver = BetterCap::Network::Servers::DNSD.new( nil, ctx.ifconfig[:ip_saddr], ctx.options.servers.dnsd_port )
109
110
 
110
111
  @resolver.start
111
112
  end
@@ -184,7 +185,7 @@ class Strip
184
185
 
185
186
  # Clean some headers from +r+.
186
187
  def process_headers!(r)
187
- what = r.is_a?(BetterCap::Proxy::Request) ? :req : :res
188
+ what = r.is_a?(BetterCap::Proxy::HTTP::Request) ? :req : :res
188
189
  HEADERS_TO_PATCH[what].each do |key,value|
189
190
  r[key] = value;
190
191
  end
@@ -321,3 +322,4 @@ end
321
322
  end
322
323
  end
323
324
  end
325
+ end
@@ -13,7 +13,9 @@ This project is released under the GPL 3 license.
13
13
 
14
14
  module BetterCap
15
15
  module Proxy
16
- # Handle data streaming between clients and servers for the BetterCap::Proxy::Proxy.
16
+ module HTTP
17
+
18
+ # Handle data streaming between clients and servers for the BetterCap::Proxy::HTTP::Proxy.
17
19
  class Streamer
18
20
  # Initialize the class.
19
21
  def initialize( sslstrip )
@@ -97,7 +99,7 @@ class Streamer
97
99
  # Run proxy modules.
98
100
  def process( request, response = nil )
99
101
  # loop each loaded module and execute if enabled
100
- BetterCap::Proxy::Module.modules.each do |mod|
102
+ BetterCap::Proxy::HTTP::Module.modules.each do |mod|
101
103
  if mod.enabled?
102
104
  # we need to save the original response in case something
103
105
  # in the module will go wrong
@@ -153,8 +155,8 @@ class Streamer
153
155
  [ client_ip, client_port ]
154
156
  end
155
157
 
156
- # Use a Net::HTTP object in order to perform the +req+ BetterCap::Proxy::Request
157
- # object, will return a BetterCap::Proxy::Response object instance.
158
+ # Use a Net::HTTP object in order to perform the +req+ BetterCap::Proxy::HTTP::Request
159
+ # object, will return a BetterCap::Proxy::HTTP::Response object instance.
158
160
  def perform_proxy_request(req, res)
159
161
  path = req.path
160
162
  response = nil
@@ -204,3 +206,4 @@ class Streamer
204
206
  end
205
207
  end
206
208
  end
209
+ end
@@ -91,10 +91,23 @@ class StreamLogger
91
91
  msg
92
92
  end
93
93
 
94
- def self.dump_raw( data )
95
- msg = ''
96
- data.each_byte do |b|
97
- msg << ( b.chr =~ /[[:print:]]/ ? b.chr : '.' ).yellow
94
+ def self.hexdump( data, opts = {} )
95
+ bytes = data
96
+ msg = ''
97
+ line_size = opts[:line_size] || 16
98
+ padding = opts[:padding] || ''
99
+
100
+ while bytes
101
+ line = bytes[0,line_size]
102
+ bytes = bytes[line_size,bytes.length]
103
+ d = ''
104
+
105
+ line.each_byte {|i| d += "%02X " % i}
106
+ d += ' ' * (line_size-line.length)
107
+ d += ' '
108
+ line.each_byte{|i| d += ( i.chr =~ /[[:print:]]/ ? i.chr : '.' ) }
109
+
110
+ msg += "#{padding}#{d}\n"
98
111
  end
99
112
  msg
100
113
  end
@@ -102,7 +115,7 @@ class StreamLogger
102
115
  def self.dump_gzip( request )
103
116
  msg = ''
104
117
  uncompressed = Zlib::GzipReader.new(StringIO.new(request.body)).read
105
- self.dump_raw( uncompressed )
118
+ self.hexdump( uncompressed )
106
119
  end
107
120
 
108
121
  def self.dump_json( request )
@@ -127,14 +140,17 @@ class StreamLogger
127
140
  when /application\/x-www-form-urlencoded.*/i
128
141
  msg << self.dump_form( request )
129
142
 
130
- when 'gzip'
143
+ when /text\/plain.*/i
144
+ msg << request.body + "\n"
145
+
146
+ when /gzip.*/i
131
147
  msg << self.dump_gzip( request )
132
148
 
133
- when 'application/json'
149
+ when /application\/json.*/i
134
150
  msg << self.dump_json( request )
135
151
 
136
152
  else
137
- msg << self.dump_raw( request.body )
153
+ msg << self.hexdump( request.body )
138
154
  end
139
155
 
140
156
  Logger.raw "#{msg}\n"
@@ -157,7 +173,7 @@ class StreamLogger
157
173
 
158
174
  Logger.raw "[#{self.addr2s(request.client)}] #{request.method.light_blue} #{request_s}#{response_s}"
159
175
  # Log post body if the POST sniffer is enabled.
160
- if Context.get.post_sniffer_enabled?
176
+ if Context.get.options.sniff.enabled?('POST')
161
177
  self.log_post( request )
162
178
  end
163
179
  end