bettercap 1.5.8 → 1.5.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: 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