bettercap 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|