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,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
|