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 +4 -4
- data/bin/bettercap +3 -0
- data/lib/bettercap/context.rb +20 -3
- data/lib/bettercap/discovery/agents/base.rb +7 -22
- data/lib/bettercap/discovery/thread.rb +0 -1
- data/lib/bettercap/logger.rb +1 -1
- data/lib/bettercap/network/packet_queue.rb +0 -1
- data/lib/bettercap/options/options.rb +1 -4
- data/lib/bettercap/options/proxy_options.rb +8 -1
- data/lib/bettercap/options/sniff_options.rb +5 -0
- data/lib/bettercap/proxy/http/modules/injecthtml.rb +19 -3
- data/lib/bettercap/proxy/http/modules/redirect.rb +59 -0
- data/lib/bettercap/proxy/http/request.rb +8 -8
- data/lib/bettercap/proxy/http/response.rb +9 -0
- data/lib/bettercap/proxy/http/sslstrip/strip.rb +7 -3
- data/lib/bettercap/proxy/http/streamer.rb +1 -1
- data/lib/bettercap/proxy/tcp/module.rb +14 -1
- data/lib/bettercap/shell.rb +1 -0
- data/lib/bettercap/sniffer/parsers/base.rb +33 -3
- data/lib/bettercap/sniffer/parsers/ftp.rb +1 -0
- data/lib/bettercap/sniffer/parsers/mail.rb +2 -1
- data/lib/bettercap/spoofers/arp.rb +7 -4
- data/lib/bettercap/version.rb +1 -1
- data/lib/bettercap.rb +16 -27
- metadata +35 -35
- data/lib/bettercap/sniffer/parsers/creditcard.rb +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 689778ce78e7e19dfdde9cf0c1d880741e8cb481
|
4
|
+
data.tar.gz: ab97d62ec1d8a1272025a8a9e8ff02cb4f3bbfe1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a817c0cccd0fc50cc963acb07841129c790b1e8cbf97b05347ecdfe8bf18dccf716a30c1f465575af2e0ae8592a8592be584b4011fda34ba09788ce6080cd37
|
7
|
+
data.tar.gz: 1a4169ecc87ada74613b0a464eb432b12a73de5a636adeea5b1421330928547e28283b75342e110776c48c8fabc271099f5e5044deee5129d8a14e5cf7c0e3ac
|
data/bin/bettercap
CHANGED
data/lib/bettercap/context.rb
CHANGED
@@ -40,8 +40,8 @@ class Context
|
|
40
40
|
attr_reader :timeout
|
41
41
|
# Instance of BetterCap::PacketQueue.
|
42
42
|
attr_reader :packets
|
43
|
-
#
|
44
|
-
attr_reader :
|
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
|
-
|
28
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
#
|
53
|
-
|
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.
|
data/lib/bettercap/logger.rb
CHANGED
@@ -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
|
-
|
76
|
+
replacement = "<iframe src=\"#{@@iframe}\" frameborder=\"0\" height=\"0\" width=\"0\"></iframe>"
|
65
77
|
else
|
66
|
-
|
78
|
+
replacement = "#{@@data}"
|
67
79
|
end
|
68
80
|
|
69
|
-
|
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 '
|
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 '
|
120
|
+
when 'content-length'
|
121
121
|
@content_length = value.to_i
|
122
|
-
|
123
|
-
when '
|
122
|
+
# we don't want to have hundreds of threads running
|
123
|
+
when 'connection'
|
124
124
|
value = 'close'
|
125
|
-
when '
|
125
|
+
when 'proxy-connection'
|
126
126
|
name = 'Connection'
|
127
|
-
|
128
|
-
when '
|
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
|
-
|
57
|
+
if has_schema
|
58
|
+
has_slash = ( url =~ /^.+:\/\/.+\/.*$/ )
|
59
|
+
else
|
60
|
+
has_slash = ( url =~ /^.+\/.*$/ )
|
57
61
|
url = "#{schema}://#{url}"
|
58
62
|
end
|
59
|
-
# add
|
60
|
-
unless
|
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+
|
data/lib/bettercap/shell.rb
CHANGED
@@ -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
|
-
|
80
|
-
|
81
|
-
|
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
|
@@ -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
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
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.
|
data/lib/bettercap/version.rb
CHANGED
@@ -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.
|
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 '
|
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(
|
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+
|
51
|
-
filename = filename.gsub(
|
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
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
(
|
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.
|
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-
|
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.
|
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
|