bettercap 1.1.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.
- checksums.yaml +7 -0
- data/LICENSE +225 -0
- data/README.md +96 -0
- data/bettercap.gemspec +28 -0
- data/bin/bettercap +184 -0
- data/example_proxy_module.rb +21 -0
- data/lib/bettercap/base/ifirewall.rb +28 -0
- data/lib/bettercap/base/ispoofer.rb +24 -0
- data/lib/bettercap/context.rb +124 -0
- data/lib/bettercap/discovery/arp.rb +37 -0
- data/lib/bettercap/discovery/icmp.rb +37 -0
- data/lib/bettercap/discovery/syn.rb +88 -0
- data/lib/bettercap/discovery/udp.rb +74 -0
- data/lib/bettercap/error.rb +16 -0
- data/lib/bettercap/factories/firewall_factory.rb +32 -0
- data/lib/bettercap/factories/parser_factory.rb +53 -0
- data/lib/bettercap/factories/spoofer_factory.rb +36 -0
- data/lib/bettercap/firewalls/linux.rb +55 -0
- data/lib/bettercap/firewalls/osx.rb +70 -0
- data/lib/bettercap/hw-prefixes +19651 -0
- data/lib/bettercap/logger.rb +53 -0
- data/lib/bettercap/monkey/packetfu/utils.rb +96 -0
- data/lib/bettercap/network.rb +131 -0
- data/lib/bettercap/proxy/module.rb +39 -0
- data/lib/bettercap/proxy/proxy.rb +262 -0
- data/lib/bettercap/proxy/request.rb +77 -0
- data/lib/bettercap/proxy/response.rb +76 -0
- data/lib/bettercap/shell.rb +31 -0
- data/lib/bettercap/sniffer/parsers/base.rb +31 -0
- data/lib/bettercap/sniffer/parsers/ftp.rb +19 -0
- data/lib/bettercap/sniffer/parsers/httpauth.rb +45 -0
- data/lib/bettercap/sniffer/parsers/https.rb +36 -0
- data/lib/bettercap/sniffer/parsers/irc.rb +19 -0
- data/lib/bettercap/sniffer/parsers/mail.rb +19 -0
- data/lib/bettercap/sniffer/parsers/ntlmss.rb +38 -0
- data/lib/bettercap/sniffer/parsers/post.rb +24 -0
- data/lib/bettercap/sniffer/parsers/url.rb +28 -0
- data/lib/bettercap/sniffer/sniffer.rb +39 -0
- data/lib/bettercap/spoofers/arp.rb +130 -0
- data/lib/bettercap/spoofers/none.rb +23 -0
- data/lib/bettercap/target.rb +52 -0
- data/lib/bettercap/version.rb +14 -0
- metadata +129 -0
@@ -0,0 +1,77 @@
|
|
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 Proxy
|
14
|
+
|
15
|
+
class Request
|
16
|
+
attr_reader :lines, :verb, :url, :host, :port, :content_length
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@lines = []
|
20
|
+
@verb = nil
|
21
|
+
@url = nil
|
22
|
+
@host = nil
|
23
|
+
@port = 80
|
24
|
+
@content_length = 0
|
25
|
+
end
|
26
|
+
|
27
|
+
def <<(line)
|
28
|
+
line = line.chomp
|
29
|
+
|
30
|
+
# is this the first line '<VERB> <URI> HTTP/<VERSION>' ?
|
31
|
+
if @url.nil? and line =~ /^(\w+)\s+(\S+)\s+HTTP\/[\d\.]+\s*$/
|
32
|
+
@verb = $1
|
33
|
+
@url = $2
|
34
|
+
|
35
|
+
# fix url
|
36
|
+
if @url.include? '://'
|
37
|
+
uri = URI::parse @url
|
38
|
+
@url = "#{uri.path}" + ( uri.query ? "?#{uri.query}" : "" )
|
39
|
+
end
|
40
|
+
|
41
|
+
line = "#{@verb} #{url} HTTP/1.0"
|
42
|
+
|
43
|
+
# get the host header value
|
44
|
+
elsif line =~ /^Host: (.*)$/
|
45
|
+
@host = $1
|
46
|
+
if host =~ /([^:]*):([0-9]*)$/
|
47
|
+
@host = $1
|
48
|
+
@port = $2.to_i
|
49
|
+
end
|
50
|
+
|
51
|
+
# parse content length, this will speed up data streaming
|
52
|
+
elsif line =~ /^Content-Length:\s+(\d+)\s*$/i
|
53
|
+
@content_length = $1.to_i
|
54
|
+
|
55
|
+
# we don't want to have hundreds of threads running
|
56
|
+
elsif line =~ /Connection: keep-alive/i
|
57
|
+
line = 'Connection: close'
|
58
|
+
|
59
|
+
# disable gzip, chunked, etc encodings
|
60
|
+
elsif line =~ /^Accept-Encoding:.*/i
|
61
|
+
line = 'Accept-Encoding: identity'
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
@lines << line
|
66
|
+
end
|
67
|
+
|
68
|
+
def is_post?
|
69
|
+
return @verb == 'POST'
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
return @lines.join("\n") + "\n"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,76 @@
|
|
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 Proxy
|
14
|
+
|
15
|
+
class Response
|
16
|
+
attr_reader :content_type, :content_length, :headers, :code, :headers_done
|
17
|
+
attr_accessor :body
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@content_type = nil
|
21
|
+
@content_length = nil
|
22
|
+
@body = ''
|
23
|
+
@code = nil
|
24
|
+
@headers = []
|
25
|
+
@headers_done = false
|
26
|
+
end
|
27
|
+
|
28
|
+
def <<(line)
|
29
|
+
# we already parsed the heders, collect response body
|
30
|
+
if @headers_done
|
31
|
+
@body += line
|
32
|
+
else
|
33
|
+
# parse the response status
|
34
|
+
if @code.nil? and line =~ /^HTTP\/[\d\.]+\s+(.+)/
|
35
|
+
@code = $1.chomp
|
36
|
+
|
37
|
+
# parse the content type
|
38
|
+
elsif line =~ /^Content-Type: ([^;]+).*/i
|
39
|
+
@content_type = $1.chomp
|
40
|
+
|
41
|
+
# parse content length
|
42
|
+
elsif line =~ /^Content-Length:\s+(\d+)\s*$/i
|
43
|
+
@content_length = $1.to_i
|
44
|
+
|
45
|
+
# last line, we're done with the headers
|
46
|
+
elsif line.chomp == ""
|
47
|
+
@headers_done = true
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
@headers << line.chomp
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def is_textual?
|
56
|
+
@content_type and ( @content_type =~ /^text\/.+/ or @content_type =~ /^application\/.+/ )
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
if is_textual?
|
61
|
+
@headers.map! do |header|
|
62
|
+
# update content length in case the body was
|
63
|
+
# modified
|
64
|
+
if header =~ /Content-Length:\s*(\d+)/i
|
65
|
+
"Content-Length: #{@body.size}"
|
66
|
+
else
|
67
|
+
header
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
@headers.join("\n") + "\n" + @body
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
=begin
|
2
|
+
BETTERCAP
|
3
|
+
Author : Simone 'evilsocket' Margaritelli
|
4
|
+
Email : evilsocket@gmail.com
|
5
|
+
Blog : http://www.evilsocket.net/
|
6
|
+
This project is released under the GPL 3 license.
|
7
|
+
=end
|
8
|
+
require 'bettercap/error'
|
9
|
+
|
10
|
+
module Shell
|
11
|
+
class << self
|
12
|
+
|
13
|
+
#return the output of command
|
14
|
+
def execute(command)
|
15
|
+
r=%x(#{command})
|
16
|
+
if $? != 0
|
17
|
+
raise BetterCap::Error, "Error, executing #{command}"
|
18
|
+
end
|
19
|
+
return r
|
20
|
+
end
|
21
|
+
|
22
|
+
def ifconfig(iface = '')
|
23
|
+
self.execute( "LANG=en && ifconfig #{iface}" )
|
24
|
+
end
|
25
|
+
|
26
|
+
def arp
|
27
|
+
self.execute( 'LANG=en && arp -a' )
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
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
|
+
require 'bettercap/logger'
|
13
|
+
require 'colorize'
|
14
|
+
|
15
|
+
class BaseParser
|
16
|
+
def initialize
|
17
|
+
@filters = []
|
18
|
+
@name = 'BASE'
|
19
|
+
end
|
20
|
+
|
21
|
+
def on_packet( pkt )
|
22
|
+
s = pkt.to_s
|
23
|
+
@filters.each do |filter|
|
24
|
+
if s =~ filter
|
25
|
+
Logger.write "[#{pkt.ip_saddr}:#{pkt.tcp_src} > #{pkt.ip_daddr}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
|
26
|
+
"[#{@name}] ".green +
|
27
|
+
pkt.payload.strip.yellow
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
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
|
+
require 'bettercap/sniffer/parsers/base'
|
13
|
+
|
14
|
+
class FtpParser < BaseParser
|
15
|
+
def initialize
|
16
|
+
@filters = [ /(USER|PASS)\s+.+/ ]
|
17
|
+
@name = 'FTP'
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,45 @@
|
|
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
|
+
require 'bettercap/sniffer/parsers/base'
|
13
|
+
require 'colorize'
|
14
|
+
require 'base64'
|
15
|
+
|
16
|
+
class HttpauthParser < BaseParser
|
17
|
+
def on_packet( pkt )
|
18
|
+
lines = pkt.to_s.split("\n")
|
19
|
+
hostname = nil
|
20
|
+
path = nil
|
21
|
+
|
22
|
+
lines.each do |line|
|
23
|
+
if line =~ /[A-Z]+\s+(\/[^\s]+)\s+HTTP\/\d\.\d/
|
24
|
+
path = $1
|
25
|
+
|
26
|
+
elsif line =~ /Host:\s*([^\s]+)/i
|
27
|
+
hostname = $1
|
28
|
+
|
29
|
+
elsif line =~ /Authorization:\s*Basic\s+([^\s]+)/i
|
30
|
+
encoded = $1
|
31
|
+
decoded = Base64.decode64(encoded)
|
32
|
+
user, pass = decoded.split(':')
|
33
|
+
|
34
|
+
Logger.write "[#{pkt.ip_saddr}:#{pkt.tcp_src} > #{pkt.ip_daddr}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
|
35
|
+
'[HTTP BASIC AUTH]'.green + " http://#{hostname}#{path} - username=#{user} password=#{pass}".yellow
|
36
|
+
|
37
|
+
elsif line =~ /Authorization:\s*Digest\s+(.+)/i
|
38
|
+
Logger.write "[#{pkt.ip_saddr}:#{pkt.tcp_src} > #{pkt.ip_daddr}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
|
39
|
+
'[HTTP DIGEST AUTH]'.green + " http://#{hostname}#{path}\n#{$1}".yellow
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,36 @@
|
|
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
|
+
require 'bettercap/sniffer/parsers/base'
|
13
|
+
require 'colorize'
|
14
|
+
require 'resolv'
|
15
|
+
|
16
|
+
class HttpsParser < BaseParser
|
17
|
+
def on_packet( pkt )
|
18
|
+
begin
|
19
|
+
if pkt.tcp_dst == 443
|
20
|
+
# the DNS resolution could take a while and block other parsers.
|
21
|
+
Thread.new do
|
22
|
+
begin
|
23
|
+
hostname = Resolv.getname pkt.ip_daddr
|
24
|
+
rescue
|
25
|
+
hostname = pkt.ip_daddr.to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
Logger.write "[#{pkt.ip_saddr}:#{pkt.tcp_src} > #{pkt.ip_daddr}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
|
29
|
+
'[HTTPS] '.green +
|
30
|
+
"https://#{hostname}/".yellow
|
31
|
+
end
|
32
|
+
end
|
33
|
+
rescue
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
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
|
+
require 'bettercap/sniffer/parsers/base'
|
13
|
+
|
14
|
+
class IrcParser < BaseParser
|
15
|
+
def initialize
|
16
|
+
@filters = [ /NICK\s+.+/, /NS IDENTIFY\s+.+/, /nickserv :identify\s+.+/ ]
|
17
|
+
@name = 'IRC'
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
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
|
+
require 'bettercap/sniffer/parsers/base'
|
13
|
+
|
14
|
+
class MailParser < BaseParser
|
15
|
+
def initialize
|
16
|
+
@filters = [ /(\d+ )?(auth|authenticate) (login|plain)/i, /(\d+ )?login/i ]
|
17
|
+
@name = 'MAIL'
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,38 @@
|
|
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
|
+
require 'bettercap/sniffer/parsers/base'
|
13
|
+
require 'colorize'
|
14
|
+
|
15
|
+
class NtlmssParser < BaseParser
|
16
|
+
def bin2hex( data )
|
17
|
+
hex = ''
|
18
|
+
data.each_byte do |byte|
|
19
|
+
if /[[:print:]]/ === byte.chr
|
20
|
+
hex += byte.chr
|
21
|
+
else
|
22
|
+
hex += "\\x" + byte.to_s(16)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
hex
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_packet( pkt )
|
30
|
+
s = pkt.to_s
|
31
|
+
if s =~ /NTLMSSP\x00\x03\x00\x00\x00.+/
|
32
|
+
# TODO: Parse NTLMSSP packet.
|
33
|
+
Logger.write "[#{pkt.ip_saddr} > #{pkt.ip_daddr} #{pkt.proto.last}] " +
|
34
|
+
'[NTLMSS] '.green +
|
35
|
+
bin2hex( pkt.payload ).yellow
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,24 @@
|
|
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
|
+
require 'bettercap/sniffer/parsers/base'
|
13
|
+
require 'colorize'
|
14
|
+
|
15
|
+
class PostParser < BaseParser
|
16
|
+
def on_packet( pkt )
|
17
|
+
s = pkt.to_s
|
18
|
+
if s =~ /POST\s+[^\s]+\s+HTTP.+/
|
19
|
+
Logger.write "[#{pkt.ip_saddr}:#{pkt.tcp_src} > #{pkt.ip_daddr}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
|
20
|
+
"[POST]\n".green +
|
21
|
+
pkt.payload.strip.yellow
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
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
|
+
require 'bettercap/sniffer/parsers/base'
|
13
|
+
require 'colorize'
|
14
|
+
|
15
|
+
class UrlParser < BaseParser
|
16
|
+
def on_packet( pkt )
|
17
|
+
s = pkt.to_s
|
18
|
+
if s =~ /GET\s+([^\s]+)\s+HTTP.+Host:\s+([^\s]+).+/m
|
19
|
+
host = $2
|
20
|
+
url = $1
|
21
|
+
if not url =~ /.+\.(png|jpg|jpeg|bmp|gif|img|ttf|woff|css|js).*/i
|
22
|
+
Logger.write "[#{pkt.ip_saddr}:#{pkt.tcp_src} > #{pkt.ip_daddr}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
|
23
|
+
'[GET] '.green +
|
24
|
+
"http://#{host}#{url}".yellow
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|