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,21 @@
|
|
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
|
+
class HackTitle < Proxy::Module
|
13
|
+
def on_request( request, response )
|
14
|
+
# is it a html page?
|
15
|
+
if response.content_type == 'text/html'
|
16
|
+
Logger.info "Hacking http://#{request.host}#{request.url} title tag"
|
17
|
+
# make sure to use sub! or gsub! to update the instance
|
18
|
+
response.body.sub!( '<title>', '<title> !!! HACKED !!! ' )
|
19
|
+
end
|
20
|
+
end
|
21
|
+
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
|
+
class IFirewall
|
13
|
+
def enable_forwarding(enabled)
|
14
|
+
raise 'IFirewall: Unimplemented method!'
|
15
|
+
end
|
16
|
+
|
17
|
+
def forwarding_enabled?()
|
18
|
+
raise 'IFirewall: Unimplemented method!'
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_port_redirection( iface, proto, from, addr, to )
|
22
|
+
raise 'IFirewall: Unimplemented method!'
|
23
|
+
end
|
24
|
+
|
25
|
+
def del_port_redirection( iface, proto, from, addr, to )
|
26
|
+
raise 'IFirewall: Unimplemented method!'
|
27
|
+
end
|
28
|
+
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
|
+
class ISpoofer
|
13
|
+
def initialize
|
14
|
+
raise 'ISpoofer: Unimplemented method!'
|
15
|
+
end
|
16
|
+
|
17
|
+
def start
|
18
|
+
raise 'ISpoofer: Unimplemented method!'
|
19
|
+
end
|
20
|
+
|
21
|
+
def stop
|
22
|
+
raise 'ISpoofer: Unimplemented method!'
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,124 @@
|
|
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
|
+
# this class holds global states & data
|
14
|
+
require 'bettercap/error'
|
15
|
+
|
16
|
+
class Context
|
17
|
+
attr_accessor :options, :iface, :ifconfig, :network, :firewall, :gateway,
|
18
|
+
:targets, :spoofer, :proxy
|
19
|
+
|
20
|
+
@@instance = nil
|
21
|
+
|
22
|
+
def self.get
|
23
|
+
if @@instance.nil?
|
24
|
+
@@instance = self.new
|
25
|
+
end
|
26
|
+
@@instance
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
@options = {
|
31
|
+
:iface => Pcap.lookupdev,
|
32
|
+
:spoofer => 'ARP',
|
33
|
+
:target => nil,
|
34
|
+
:logfile => nil,
|
35
|
+
:sniffer => false,
|
36
|
+
:parsers => ['*'],
|
37
|
+
:local => false,
|
38
|
+
:debug => false,
|
39
|
+
:arpcache => false,
|
40
|
+
:proxy => false,
|
41
|
+
:proxy_port => 8080,
|
42
|
+
:proxy_module => nil
|
43
|
+
}
|
44
|
+
|
45
|
+
@iface = nil
|
46
|
+
@ifconfig = nil
|
47
|
+
@network = nil
|
48
|
+
@firewall = FirewallFactory.get_firewall
|
49
|
+
@gateway = nil
|
50
|
+
@targets = []
|
51
|
+
@proxy = nil
|
52
|
+
@spoofer = nil
|
53
|
+
|
54
|
+
@discovery_running = false
|
55
|
+
@discovery_thread = nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def update_network
|
59
|
+
@iface = PacketFu::Utils.whoami? :iface => @options[:iface]
|
60
|
+
@ifconfig = PacketFu::Utils.ifconfig @options[:iface]
|
61
|
+
@network = @ifconfig[:ip4_obj]
|
62
|
+
@gateway = Network.get_gateway
|
63
|
+
|
64
|
+
raise BetterCap::Error, "Could not determine IPv4 address of '#{@options[:iface]}' interface." unless !@network.nil?
|
65
|
+
|
66
|
+
Logger.debug "network=#{@network} gateway=#{@gateway} local_ip=#{@iface[:ip_saddr]}"
|
67
|
+
Logger.debug "IFCONFIG: #{@ifconfig.inspect}"
|
68
|
+
Logger.debug "IFACE: #{@iface.inspect}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def start_discovery_thread
|
72
|
+
@discovery_running = true
|
73
|
+
@discovery_thread = Thread.new {
|
74
|
+
Logger.info 'Network discovery thread started.'
|
75
|
+
|
76
|
+
while @discovery_running
|
77
|
+
empty_list = false
|
78
|
+
|
79
|
+
if @targets.size == 0 and !@options[:arpcache]
|
80
|
+
empty_list = true
|
81
|
+
Logger.info 'Searching for alive targets ...'
|
82
|
+
end
|
83
|
+
|
84
|
+
@targets = Network.get_alive_targets self
|
85
|
+
|
86
|
+
if empty_list and !@options[:arpcache]
|
87
|
+
Logger.info "Collected #{@targets.size} total targets."
|
88
|
+
@targets.each do |target|
|
89
|
+
Logger.info " #{target}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
def stop_discovery_thread
|
97
|
+
@discovery_running = false
|
98
|
+
if @discovery_thread != nil
|
99
|
+
Logger.info 'Stopping network discovery thread ...'
|
100
|
+
|
101
|
+
begin
|
102
|
+
@discovery_thread.join
|
103
|
+
rescue
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def finalize
|
109
|
+
stop_discovery_thread
|
110
|
+
|
111
|
+
if !@spoofer.nil?
|
112
|
+
@spoofer.stop
|
113
|
+
end
|
114
|
+
|
115
|
+
if !@proxy.nil?
|
116
|
+
@proxy.stop
|
117
|
+
@firewall.del_port_redirection( @options[:iface], 'TCP', 80, @iface[:ip_saddr], @options[:proxy_port] )
|
118
|
+
end
|
119
|
+
|
120
|
+
if !@firewall.nil?
|
121
|
+
@firewall.enable_forwarding(false)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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 'bettercap/shell'
|
14
|
+
require 'bettercap/target'
|
15
|
+
|
16
|
+
# Parse the ARP table searching for new hosts.
|
17
|
+
class ArpAgent
|
18
|
+
def self.parse( ctx )
|
19
|
+
arp = Shell.arp
|
20
|
+
targets = []
|
21
|
+
|
22
|
+
Logger.debug "ARP:\n#{arp}"
|
23
|
+
|
24
|
+
arp.split("\n").each do |line|
|
25
|
+
m = /[^\s]+\s+\(([0-9\.]+)\)\s+at\s+([a-f0-9:]+).+#{ctx.ifconfig[:iface]}.*/i.match(line)
|
26
|
+
if !m.nil?
|
27
|
+
if m[1] != ctx.gateway and m[1] != ctx.iface[:ip_saddr] and m[2] != 'ff:ff:ff:ff:ff:ff'
|
28
|
+
target = Target.new( m[1], m[2] )
|
29
|
+
targets << target
|
30
|
+
Logger.debug "FOUND #{target}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
targets
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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 'bettercap/shell'
|
14
|
+
require 'bettercap/factories/firewall_factory'
|
15
|
+
|
16
|
+
# Send a broadcast ping trying to filling the ARP table.
|
17
|
+
class IcmpAgent
|
18
|
+
def initialize( timeout = 5 )
|
19
|
+
@thread = Thread.new do
|
20
|
+
FirewallFactory.get_firewall.enable_icmp_bcast(true)
|
21
|
+
|
22
|
+
if RUBY_PLATFORM =~ /darwin/
|
23
|
+
ping = Shell.execute("ping -i #{timeout} -c 2 255.255.255.255")
|
24
|
+
elsif RUBY_PLATFORM =~ /linux/
|
25
|
+
ping = Shell.execute("ping -i #{timeout} -c 2 -b 255.255.255.255")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def wait
|
31
|
+
begin
|
32
|
+
@thread.join
|
33
|
+
rescue Exception => e
|
34
|
+
Logger.debug "IcmpAgent.wait: #{e.message}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,88 @@
|
|
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
|
+
|
14
|
+
# Send SYN probes trying to filling the ARP table.
|
15
|
+
class SynAgent
|
16
|
+
def initialize( ifconfig, gw_ip, local_ip )
|
17
|
+
@local_ip = local_ip
|
18
|
+
@ifconfig = ifconfig
|
19
|
+
@queue = Queue.new
|
20
|
+
|
21
|
+
net = ip = @ifconfig[:ip4_obj]
|
22
|
+
|
23
|
+
# loop each ip in our subnet and push it to the queue
|
24
|
+
while net.include?ip
|
25
|
+
# rescanning the gateway could cause an issue when the
|
26
|
+
# gateway itself has multiple interfaces ( LAN, WAN ... )
|
27
|
+
if ip != gw_ip and ip != local_ip
|
28
|
+
@queue.push ip
|
29
|
+
end
|
30
|
+
|
31
|
+
ip = ip.succ
|
32
|
+
end
|
33
|
+
|
34
|
+
# spawn the workers! ( tnx to https://blog.engineyard.com/2014/ruby-thread-pool )
|
35
|
+
@workers = (0...4).map do
|
36
|
+
Thread.new do
|
37
|
+
begin
|
38
|
+
while ip = @queue.pop(true)
|
39
|
+
Logger.debug "SYN Probing #{ip} ..."
|
40
|
+
|
41
|
+
pkt = get_packet ip.to_s
|
42
|
+
|
43
|
+
pkt.to_w( @ifconfig[:iface] )
|
44
|
+
end
|
45
|
+
rescue Exception => e
|
46
|
+
Logger.debug "#{ip} -> #{e.message}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def wait
|
53
|
+
begin
|
54
|
+
@workers.map(&:join)
|
55
|
+
rescue Exception => e
|
56
|
+
Logger.debug "SynAgent.wait: #{e.message}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def get_packet( destination )
|
63
|
+
pkt = PacketFu::TCPPacket.new
|
64
|
+
pkt.ip_v = 4
|
65
|
+
pkt.ip_hl = 5
|
66
|
+
pkt.ip_tos = 0
|
67
|
+
pkt.ip_len = 20
|
68
|
+
pkt.ip_frag = 0
|
69
|
+
pkt.ip_ttl = 115
|
70
|
+
pkt.ip_proto = 6 # TCP
|
71
|
+
pkt.ip_saddr = @local_ip
|
72
|
+
pkt.ip_daddr = destination
|
73
|
+
pkt.payload = "\xC\x0\xF\xF\xE\xE"
|
74
|
+
pkt.tcp_flags.ack = 0
|
75
|
+
pkt.tcp_flags.fin = 0
|
76
|
+
pkt.tcp_flags.psh = 0
|
77
|
+
pkt.tcp_flags.rst = 0
|
78
|
+
pkt.tcp_flags.syn = 1
|
79
|
+
pkt.tcp_flags.urg = 0
|
80
|
+
pkt.tcp_ecn = 0
|
81
|
+
pkt.tcp_win = 8192
|
82
|
+
pkt.tcp_hlen = 5
|
83
|
+
pkt.tcp_dst = rand(1024..65535)
|
84
|
+
pkt.recalc
|
85
|
+
pkt
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
@@ -0,0 +1,74 @@
|
|
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
|
+
|
14
|
+
# Send UDP probes trying to filling the ARP table.
|
15
|
+
class UdpAgent
|
16
|
+
def initialize( ifconfig, gw_ip, local_ip )
|
17
|
+
@ifconfig = ifconfig
|
18
|
+
@port = 137
|
19
|
+
@message =
|
20
|
+
"\x82\x28\x00\x00\x00" +
|
21
|
+
"\x01\x00\x00\x00\x00" +
|
22
|
+
"\x00\x00\x20\x43\x4B" +
|
23
|
+
"\x41\x41\x41\x41\x41" +
|
24
|
+
"\x41\x41\x41\x41\x41" +
|
25
|
+
"\x41\x41\x41\x41\x41" +
|
26
|
+
"\x41\x41\x41\x41\x41" +
|
27
|
+
"\x41\x41\x41\x41\x41" +
|
28
|
+
"\x41\x41\x41\x41\x41" +
|
29
|
+
"\x00\x00\x21\x00\x01"
|
30
|
+
|
31
|
+
@queue = Queue.new
|
32
|
+
|
33
|
+
net = ip = @ifconfig[:ip4_obj]
|
34
|
+
|
35
|
+
# loop each ip in our subnet and push it to the queue
|
36
|
+
while net.include?ip
|
37
|
+
# rescanning the gateway could cause an issue when the
|
38
|
+
# gateway itself has multiple interfaces ( LAN, WAN ... )
|
39
|
+
if ip != gw_ip and ip != local_ip
|
40
|
+
@queue.push ip
|
41
|
+
end
|
42
|
+
|
43
|
+
ip = ip.succ
|
44
|
+
end
|
45
|
+
|
46
|
+
# spawn the workers! ( tnx to https://blog.engineyard.com/2014/ruby-thread-pool )
|
47
|
+
@workers = (0...4).map do
|
48
|
+
Thread.new do
|
49
|
+
begin
|
50
|
+
while ip = @queue.pop(true)
|
51
|
+
Logger.debug "Probing #{ip} ..."
|
52
|
+
|
53
|
+
# send netbios udp packet, just to fill ARP table
|
54
|
+
sd = UDPSocket.new
|
55
|
+
sd.send( @message, 0, ip.to_s, @port )
|
56
|
+
sd = nil
|
57
|
+
# TODO: Parse response for hostname?
|
58
|
+
end
|
59
|
+
rescue Exception => e
|
60
|
+
Logger.debug "#{ip} -> #{e.message}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def wait
|
67
|
+
begin
|
68
|
+
@workers.map(&:join)
|
69
|
+
rescue Exception => e
|
70
|
+
Logger.debug "UdpAgent.wait: #{e.message}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
@@ -0,0 +1,16 @@
|
|
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
|
+
# class used to distinghuish between handled and unhandled exceptions
|
14
|
+
module BetterCap
|
15
|
+
class Error < StandardError; end
|
16
|
+
end
|