xettercap 1.5.7xerob
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/xettercap +61 -0
- data/lib/bettercap/banner +2 -0
- data/lib/bettercap/context.rb +259 -0
- data/lib/bettercap/discovery/agents/arp.rb +37 -0
- data/lib/bettercap/discovery/agents/base.rb +73 -0
- data/lib/bettercap/discovery/agents/icmp.rb +44 -0
- data/lib/bettercap/discovery/agents/udp.rb +30 -0
- data/lib/bettercap/discovery/thread.rb +128 -0
- data/lib/bettercap/error.rb +16 -0
- data/lib/bettercap/firewalls/base.rb +103 -0
- data/lib/bettercap/firewalls/bsd.rb +74 -0
- data/lib/bettercap/firewalls/linux.rb +65 -0
- data/lib/bettercap/firewalls/redirection.rb +42 -0
- data/lib/bettercap/loader.rb +27 -0
- data/lib/bettercap/logger.rb +131 -0
- data/lib/bettercap/memory.rb +56 -0
- data/lib/bettercap/monkey/celluloid/actor.rb +23 -0
- data/lib/bettercap/monkey/celluloid/io/udp_socket.rb +26 -0
- data/lib/bettercap/monkey/em-proxy/proxy.rb +23 -0
- data/lib/bettercap/monkey/openssl/server.rb +35 -0
- data/lib/bettercap/monkey/packetfu/pcap.rb +51 -0
- data/lib/bettercap/monkey/packetfu/utils.rb +210 -0
- data/lib/bettercap/monkey/system.rb +25 -0
- data/lib/bettercap/network/arp_reader.rb +91 -0
- data/lib/bettercap/network/hw-prefixes +21326 -0
- data/lib/bettercap/network/network.rb +102 -0
- data/lib/bettercap/network/packet_queue.rb +129 -0
- data/lib/bettercap/network/protos/base.rb +154 -0
- data/lib/bettercap/network/protos/dhcp.rb +227 -0
- data/lib/bettercap/network/protos/mysql.rb +40 -0
- data/lib/bettercap/network/protos/ntlm.rb +97 -0
- data/lib/bettercap/network/protos/snmp.rb +49 -0
- data/lib/bettercap/network/protos/teamviewer.rb +119 -0
- data/lib/bettercap/network/servers/dnsd.rb +152 -0
- data/lib/bettercap/network/servers/httpd.rb +55 -0
- data/lib/bettercap/network/services +2182 -0
- data/lib/bettercap/network/target.rb +168 -0
- data/lib/bettercap/network/validator.rb +96 -0
- data/lib/bettercap/options/core_options.rb +197 -0
- data/lib/bettercap/options/options.rb +165 -0
- data/lib/bettercap/options/proxy_options.rb +314 -0
- data/lib/bettercap/options/server_options.rb +73 -0
- data/lib/bettercap/options/sniff_options.rb +90 -0
- data/lib/bettercap/options/spoof_options.rb +71 -0
- data/lib/bettercap/pluggable.rb +37 -0
- data/lib/bettercap/proxy/http/module.rb +105 -0
- data/lib/bettercap/proxy/http/modules/injectcss.rb +79 -0
- data/lib/bettercap/proxy/http/modules/injecthtml.rb +80 -0
- data/lib/bettercap/proxy/http/modules/injectjs.rb +79 -0
- data/lib/bettercap/proxy/http/proxy.rb +184 -0
- data/lib/bettercap/proxy/http/request.rb +192 -0
- data/lib/bettercap/proxy/http/response.rb +226 -0
- data/lib/bettercap/proxy/http/ssl/authority.rb +182 -0
- data/lib/bettercap/proxy/http/ssl/bettercap-ca.pem +49 -0
- data/lib/bettercap/proxy/http/ssl/server.rb +63 -0
- data/lib/bettercap/proxy/http/sslstrip/cookiemonitor.rb +67 -0
- data/lib/bettercap/proxy/http/sslstrip/lock.ico +0 -0
- data/lib/bettercap/proxy/http/sslstrip/strip.rb +325 -0
- data/lib/bettercap/proxy/http/streamer.rb +225 -0
- data/lib/bettercap/proxy/stream_logger.rb +181 -0
- data/lib/bettercap/proxy/tcp/module.rb +75 -0
- data/lib/bettercap/proxy/tcp/proxy.rb +123 -0
- data/lib/bettercap/proxy/thread_pool.rb +194 -0
- data/lib/bettercap/shell.rb +70 -0
- data/lib/bettercap/sniffer/parsers/base.rb +87 -0
- data/lib/bettercap/sniffer/parsers/cookie.rb +45 -0
- data/lib/bettercap/sniffer/parsers/creditcard.rb +62 -0
- data/lib/bettercap/sniffer/parsers/custom.rb +26 -0
- data/lib/bettercap/sniffer/parsers/dhcp.rb +45 -0
- data/lib/bettercap/sniffer/parsers/dict.rb +37 -0
- data/lib/bettercap/sniffer/parsers/ftp.rb +24 -0
- data/lib/bettercap/sniffer/parsers/httpauth.rb +44 -0
- data/lib/bettercap/sniffer/parsers/https.rb +42 -0
- data/lib/bettercap/sniffer/parsers/irc.rb +24 -0
- data/lib/bettercap/sniffer/parsers/mail.rb +24 -0
- data/lib/bettercap/sniffer/parsers/mpd.rb +36 -0
- data/lib/bettercap/sniffer/parsers/mysql.rb +27 -0
- data/lib/bettercap/sniffer/parsers/nntp.rb +24 -0
- data/lib/bettercap/sniffer/parsers/ntlmss.rb +34 -0
- data/lib/bettercap/sniffer/parsers/pgsql.rb +36 -0
- data/lib/bettercap/sniffer/parsers/post.rb +33 -0
- data/lib/bettercap/sniffer/parsers/redis.rb +39 -0
- data/lib/bettercap/sniffer/parsers/rlogin.rb +45 -0
- data/lib/bettercap/sniffer/parsers/snmp.rb +44 -0
- data/lib/bettercap/sniffer/parsers/snpp.rb +37 -0
- data/lib/bettercap/sniffer/parsers/teamviewer.rb +30 -0
- data/lib/bettercap/sniffer/parsers/url.rb +30 -0
- data/lib/bettercap/sniffer/parsers/whatsapp.rb +33 -0
- data/lib/bettercap/sniffer/sniffer.rb +142 -0
- data/lib/bettercap/spoofers/arp.rb +150 -0
- data/lib/bettercap/spoofers/base.rb +152 -0
- data/lib/bettercap/spoofers/icmp.rb +202 -0
- data/lib/bettercap/spoofers/none.rb +57 -0
- data/lib/bettercap/update_checker.rb +57 -0
- data/lib/bettercap/version.rb +18 -0
- data/lib/bettercap.rb +70 -0
- metadata +276 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bbfc85fac2603c848498feb4a8acd1ea7bba9ebecfbf22b053b374138db3a272
|
4
|
+
data.tar.gz: f45da6057ca6f78421932054270e47258643d68905d632d438e09c8874b637b7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b24afaa692025254897bd1aaa78759847f86e5a55d2b49507bd779965fc286a6d8298b26e44569ac6ce42b6cf739134116ee4678c6c589896a67a32cb9554ce8
|
7
|
+
data.tar.gz: 3615020fca5dff0349202c8355becf5fccc507edec430a6289c890221c439aea00f6aff6fc88f3caff9d23a5ef57d8f91541b341a8cf504d1bc98ac1a354b92d
|
data/bin/xettercap
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
=begin
|
5
|
+
|
6
|
+
BETTERCAP
|
7
|
+
|
8
|
+
Author : Simone 'evilsocket' Margaritelli
|
9
|
+
Email : evilsocket@gmail.com
|
10
|
+
Blog : http://www.evilsocket.net/
|
11
|
+
|
12
|
+
This project is released under the GPL 3 license.
|
13
|
+
|
14
|
+
=end
|
15
|
+
|
16
|
+
require 'bettercap'
|
17
|
+
begin
|
18
|
+
|
19
|
+
# We need this in order to report unhandled exceptions.
|
20
|
+
|
21
|
+
|
22
|
+
# Create global context, parse command line arguments and perform basic
|
23
|
+
# error checking.
|
24
|
+
ctx = BetterCap::Options.parse!
|
25
|
+
|
26
|
+
ctx.start!
|
27
|
+
|
28
|
+
loop do
|
29
|
+
sleep 10
|
30
|
+
end
|
31
|
+
|
32
|
+
rescue SystemExit, Interrupt, SignalException
|
33
|
+
BetterCap::Logger.raw "\n"
|
34
|
+
|
35
|
+
rescue OptionParser::InvalidOption,
|
36
|
+
OptionParser::AmbiguousOption,
|
37
|
+
OptionParser::MissingArgument => e
|
38
|
+
BetterCap::Logger.error "'#{e.message.capitalize}', verify your command line arguments executing 'bettercap --help'."
|
39
|
+
|
40
|
+
rescue BetterCap::Error => e
|
41
|
+
BetterCap::Logger.error e.message
|
42
|
+
|
43
|
+
rescue Exception => e
|
44
|
+
puts "\n\n"
|
45
|
+
BetterCap::Logger.error "Oooops, seems like something weird occurred, please copy paste the following output " \
|
46
|
+
"and open a new issue on https://github.com/evilsocket/bettercap/issues :\n"
|
47
|
+
|
48
|
+
BetterCap::Logger.error "Platform : #{RUBY_PLATFORM}"
|
49
|
+
BetterCap::Logger.error "Ruby Version : #{RUBY_VERSION}"
|
50
|
+
BetterCap::Logger.error "BetterCap Version : #{BetterCap::VERSION}"
|
51
|
+
BetterCap::Logger.error "Command Line : #{original_argv.join(" ")}"
|
52
|
+
BetterCap::Logger.error "Exception : #{e.class}"
|
53
|
+
BetterCap::Logger.error "Message : #{e.message}"
|
54
|
+
BetterCap::Logger.error "Backtrace :\n\n #{e.backtrace.join("\n ")}\n"
|
55
|
+
|
56
|
+
ensure
|
57
|
+
# Make sure all the messages on the logger queue are printed.
|
58
|
+
BetterCap::Logger.wait!
|
59
|
+
|
60
|
+
ctx.finalize unless ctx.nil?
|
61
|
+
end
|
@@ -0,0 +1,259 @@
|
|
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
|
+
module BetterCap
|
15
|
+
# This class holds global states and data, moreover it exposes high level
|
16
|
+
# methods to manipulate the program behaviour.
|
17
|
+
class Context
|
18
|
+
# Instance of BetterCap::Options class.
|
19
|
+
attr_accessor :options
|
20
|
+
# Instance of the current BetterCap::Firewalls class.
|
21
|
+
attr_accessor :firewall
|
22
|
+
# Local interface ( as an instance of BetterCap::Network::Target ).
|
23
|
+
attr_accessor :iface
|
24
|
+
# Network gateway ( as an instance of BetterCap::Network::Target ).
|
25
|
+
attr_accessor :gateway
|
26
|
+
# A list of BetterCap::Target objects which is periodically updated.
|
27
|
+
attr_accessor :targets
|
28
|
+
# Instance of BetterCap::Discovery::Thread class.
|
29
|
+
attr_accessor :discovery
|
30
|
+
# A list of BetterCap::Spoofers class instances.
|
31
|
+
attr_accessor :spoofer
|
32
|
+
# Instance of BetterCap::Network::Servers::HTTPD class.
|
33
|
+
attr_accessor :httpd
|
34
|
+
# Instance of BetterCap::Network::Servers::DNSD class.
|
35
|
+
attr_accessor :dnsd
|
36
|
+
# Set to true if the program is running, to false if a shutdown was
|
37
|
+
# scheduled by the user which pressed CTRL+C
|
38
|
+
attr_accessor :running
|
39
|
+
# Timeout for discovery operations.
|
40
|
+
attr_reader :timeout
|
41
|
+
# Instance of BetterCap::PacketQueue.
|
42
|
+
attr_reader :packets
|
43
|
+
# Instance of BetterCap::Memory.
|
44
|
+
attr_reader :memory
|
45
|
+
|
46
|
+
@@instance = nil
|
47
|
+
|
48
|
+
# Return the global instance of the program Context, if the instance
|
49
|
+
# was not yet created it will be initialized and returned.
|
50
|
+
def self.get
|
51
|
+
@@instance ||= self.new
|
52
|
+
end
|
53
|
+
|
54
|
+
# Initialize the global context object.
|
55
|
+
def initialize
|
56
|
+
begin
|
57
|
+
iface = PCAPRUB::Pcap.lookupdev
|
58
|
+
rescue Exception => e
|
59
|
+
iface = nil
|
60
|
+
Logger.exception e
|
61
|
+
end
|
62
|
+
|
63
|
+
@running = true
|
64
|
+
@timeout = 5
|
65
|
+
@options = Options.new iface
|
66
|
+
@discovery = Discovery::Thread.new self
|
67
|
+
@firewall = Firewalls::Base.get
|
68
|
+
@memory = Memory.new
|
69
|
+
@iface = nil
|
70
|
+
@original_mac = nil
|
71
|
+
@gateway = nil
|
72
|
+
@targets = []
|
73
|
+
@spoofer = nil
|
74
|
+
@httpd = nil
|
75
|
+
@dnsd = nil
|
76
|
+
@proxies = []
|
77
|
+
@redirections = []
|
78
|
+
@packets = nil
|
79
|
+
end
|
80
|
+
|
81
|
+
# Update the Context state parsing network related informations.
|
82
|
+
def update!
|
83
|
+
gw = @options.core.gateway || Network.get_gateway
|
84
|
+
raise BetterCap::Error, "Could not detect the gateway address for interface #{@options.core.iface}, "\
|
85
|
+
'make sure you\'ve specified the correct network interface to use and to have the '\
|
86
|
+
'correct network configuration, this could also happen if bettercap '\
|
87
|
+
'is launched from a virtual environment.' unless Network::Validator.is_ip?(gw)
|
88
|
+
|
89
|
+
unless @options.core.use_mac.nil?
|
90
|
+
cfg = PacketFu::Utils.ifconfig @options.core.iface
|
91
|
+
raise BetterCap::Error, "Could not determine IPv4 address of '#{@options.core.iface}', make sure this interface "\
|
92
|
+
'is active and connected.' if cfg[:ip4_obj].nil?
|
93
|
+
|
94
|
+
@original_mac = Network::Target.normalized_mac(cfg[:eth_saddr])
|
95
|
+
|
96
|
+
Logger.info "Changing interface MAC address to #{@options.core.use_mac}"
|
97
|
+
|
98
|
+
Shell.ifconfig( "#{@options.core.iface} ether #{@options.core.use_mac}")
|
99
|
+
end
|
100
|
+
|
101
|
+
cfg = PacketFu::Utils.ifconfig @options.core.iface
|
102
|
+
raise BetterCap::Error, "Could not determine IPv4 address of '#{@options.core.iface}', make sure this interface "\
|
103
|
+
'is active and connected.' if cfg[:ip4_obj].nil?
|
104
|
+
|
105
|
+
@gateway = Network::Target.new gw
|
106
|
+
@targets = @options.core.targets unless @options.core.targets.nil?
|
107
|
+
@iface = Network::Target.new( cfg[:ip_saddr], cfg[:eth_saddr], cfg[:ip4_obj], cfg[:iface] )
|
108
|
+
|
109
|
+
###Logger.info "[#{@iface.name.green}] #{@iface.to_s(false)}"
|
110
|
+
|
111
|
+
Logger.debug '----- NETWORK INFORMATIONS -----'
|
112
|
+
Logger.debug " network = #{@iface.network} ( #{@iface.network.to_range.to_s.split('..').join( ' -> ')} )"
|
113
|
+
Logger.debug " gateway = #{@gateway.ip}"
|
114
|
+
Logger.debug " local_ip = #{@iface.ip}"
|
115
|
+
Logger.debug "--------------------------------\n"
|
116
|
+
|
117
|
+
@packets = Network::PacketQueue.new( @iface.name, @options.core.packet_throttle, 4 )
|
118
|
+
# Spoofers need the context network data to be initialized.
|
119
|
+
@spoofer = @options.spoof.parse_spoofers
|
120
|
+
end
|
121
|
+
|
122
|
+
# Find a target given its +ip+ and +mac+ addresses inside the #targets
|
123
|
+
# list, if not found return nil.
|
124
|
+
def find_target ip, mac
|
125
|
+
@targets.each do |target|
|
126
|
+
if target.equals?(ip,mac)
|
127
|
+
return target
|
128
|
+
end
|
129
|
+
end
|
130
|
+
nil
|
131
|
+
end
|
132
|
+
|
133
|
+
# Start everything!
|
134
|
+
def start!
|
135
|
+
# Start targets auto discovery.
|
136
|
+
@discovery.start
|
137
|
+
|
138
|
+
# Start network spoofers if any.
|
139
|
+
@spoofer.each do |spoofer|
|
140
|
+
spoofer.start
|
141
|
+
end
|
142
|
+
|
143
|
+
# Start proxies and setup port redirection.
|
144
|
+
if @options.proxies.any?
|
145
|
+
if ( @options.proxies.proxy or @options.proxies.proxy_https ) and @options.sniff.enabled?('URL')
|
146
|
+
BetterCap::Logger.warn "WARNING: Both HTTP transparent proxy and URL parser are enabled, you're gonna see duplicated logs."
|
147
|
+
end
|
148
|
+
create_proxies!
|
149
|
+
end
|
150
|
+
|
151
|
+
enable_port_redirection!
|
152
|
+
|
153
|
+
create_servers!
|
154
|
+
|
155
|
+
# Start network sniffer.
|
156
|
+
if @options.sniff.enabled?
|
157
|
+
Sniffer.start self
|
158
|
+
elsif @options.spoof.enabled? and !@options.proxies.any?
|
159
|
+
Logger.warn 'WARNING: Sniffer module was NOT enabled ( -X argument ), this '\
|
160
|
+
'will cause the MITM to run but no data to be collected.'
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Stop every running daemon that was started and reset system state.
|
165
|
+
def finalize
|
166
|
+
@running = false
|
167
|
+
|
168
|
+
# Logger is silent if @running == false
|
169
|
+
puts "\nStopping MITM attack ...\n"
|
170
|
+
|
171
|
+
Logger.debug 'Stopping target discovery manager ...'
|
172
|
+
@discovery.stop
|
173
|
+
|
174
|
+
Logger.debug 'Stopping spoofers ...'
|
175
|
+
@spoofer.each do |spoofer|
|
176
|
+
spoofer.stop
|
177
|
+
end
|
178
|
+
|
179
|
+
# Spoofer might be sending some last packets to restore the targets,
|
180
|
+
# the packet queue must be stopped here.
|
181
|
+
@packets.stop
|
182
|
+
|
183
|
+
Logger.debug 'Stopping proxies ...'
|
184
|
+
@proxies.each do |proxy|
|
185
|
+
proxy.stop
|
186
|
+
end
|
187
|
+
|
188
|
+
Logger.debug 'Disabling port redirections ...'
|
189
|
+
@redirections.each do |r|
|
190
|
+
@firewall.del_port_redirection( r )
|
191
|
+
end
|
192
|
+
|
193
|
+
Logger.debug 'Restoring firewall state ...'
|
194
|
+
@firewall.restore
|
195
|
+
|
196
|
+
@dnsd.stop unless @dnsd.nil?
|
197
|
+
@httpd.stop unless @httpd.nil?
|
198
|
+
|
199
|
+
Shell.ifconfig( "#{@options.core.iface} ether #{@original_mac}") unless @original_mac.nil?
|
200
|
+
end
|
201
|
+
|
202
|
+
private
|
203
|
+
|
204
|
+
# Apply needed BetterCap::Firewalls::Redirection objects.
|
205
|
+
def enable_port_redirection!
|
206
|
+
@redirections = @options.get_redirections(@iface)
|
207
|
+
@redirections.each do |r|
|
208
|
+
Logger.debug "Redirecting #{r.protocol} traffic from #{r.src_address.nil? ? '*' : r.src_address}:#{r.src_port} to #{r.dst_address}:#{r.dst_port}"
|
209
|
+
@firewall.add_port_redirection( r )
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Initialize the needed transparent proxies and the processor routined which
|
214
|
+
# is needed in order to run proxy modules.
|
215
|
+
def create_proxies!
|
216
|
+
if @options.proxies.has_proxy_module?
|
217
|
+
Proxy::HTTP::Module.register_modules
|
218
|
+
raise BetterCap::Error, "#{@options.proxies.proxy_module} is not a valid bettercap proxy module." if Proxy::HTTP::Module.modules.empty?
|
219
|
+
end
|
220
|
+
|
221
|
+
# create HTTP proxy
|
222
|
+
if @options.proxies.proxy
|
223
|
+
@proxies << Proxy::HTTP::Proxy.new( @iface.ip, @options.proxies.proxy_port, false )
|
224
|
+
end
|
225
|
+
|
226
|
+
# create HTTPS proxy
|
227
|
+
if @options.proxies.proxy_https
|
228
|
+
@proxies << Proxy::HTTP::Proxy.new( @iface.ip, @options.proxies.proxy_https_port, true )
|
229
|
+
end
|
230
|
+
|
231
|
+
# create TCP proxy
|
232
|
+
if @options.proxies.tcp_proxy
|
233
|
+
@proxies << Proxy::TCP::Proxy.new( @iface.ip, @options.proxies.tcp_proxy_port, @options.proxies.tcp_proxy_upstream_address, @options.proxies.tcp_proxy_upstream_port )
|
234
|
+
end
|
235
|
+
|
236
|
+
@proxies.each do |proxy|
|
237
|
+
proxy.start
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# Initialize and start the needed servers.
|
242
|
+
def create_servers!
|
243
|
+
# Start local DNS server.
|
244
|
+
if @options.servers.dnsd
|
245
|
+
Logger.warn "Starting DNS server with spoofing disabled, bettercap will only reply to local DNS queries." unless @options.spoof.enabled?
|
246
|
+
|
247
|
+
@dnsd = Network::Servers::DNSD.new( @options.servers.dnsd_file, @iface.ip, @options.servers.dnsd_port )
|
248
|
+
@dnsd.start
|
249
|
+
end
|
250
|
+
|
251
|
+
# Start local HTTP server.
|
252
|
+
if @options.servers.httpd
|
253
|
+
@httpd = Network::Servers::HTTPD.new( @options.servers.httpd_port, @options.servers.httpd_path )
|
254
|
+
@httpd.start
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|
259
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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
|
+
# Parse the ARP table searching for new hosts.
|
15
|
+
module BetterCap
|
16
|
+
module Discovery
|
17
|
+
module Agents
|
18
|
+
# Class responsible of sending ARP probes to each possible IP on the network.
|
19
|
+
class Arp < Discovery::Agents::Base
|
20
|
+
private
|
21
|
+
|
22
|
+
# Build a PacketFu::ARPPacket instance for the specified +ip+ address.
|
23
|
+
def get_probe( ip )
|
24
|
+
pkt = PacketFu::ARPPacket.new
|
25
|
+
|
26
|
+
pkt.eth_saddr = pkt.arp_saddr_mac = @ctx.iface.mac
|
27
|
+
pkt.eth_daddr = 'ff:ff:ff:ff:ff:ff'
|
28
|
+
pkt.arp_daddr_mac = '00:00:00:00:00:00'
|
29
|
+
pkt.arp_saddr_ip = @ctx.iface.ip
|
30
|
+
pkt.arp_daddr_ip = ip.to_s
|
31
|
+
|
32
|
+
pkt
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,73 @@
|
|
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
|
+
# Base class for discovery agents.
|
15
|
+
module BetterCap
|
16
|
+
module Discovery
|
17
|
+
module Agents
|
18
|
+
# Base class for BetterCap::Discovery::Agents.
|
19
|
+
class Base
|
20
|
+
# Initialize the agent using the +ctx+ BetterCap::Context instance.
|
21
|
+
# If +address+ is not nil only that ip will be probed.
|
22
|
+
def initialize( ctx, address = nil )
|
23
|
+
@ctx = ctx
|
24
|
+
@address = address
|
25
|
+
|
26
|
+
if @address.nil?
|
27
|
+
net = ip = @ctx.iface.network
|
28
|
+
# loop each ip in our subnet and push it to the queue
|
29
|
+
while net.include?ip
|
30
|
+
unless skip_address?(ip)
|
31
|
+
@ctx.packets.push( get_probe(ip) )
|
32
|
+
end
|
33
|
+
ip = ip.succ
|
34
|
+
end
|
35
|
+
else
|
36
|
+
if skip_address?(@address)
|
37
|
+
Logger.debug "Skipping #{@address} ..."
|
38
|
+
else
|
39
|
+
Logger.debug "Probing #{@address} ..."
|
40
|
+
@ctx.packets.push( get_probe(@address) )
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Return true if +ip+ must be skipped during discovery, otherwise false.
|
48
|
+
def skip_address?(ip)
|
49
|
+
# don't send probes to the gateway if we already have its MAC.
|
50
|
+
if ip == @ctx.gateway.ip
|
51
|
+
return !@ctx.gateway.mac.nil?
|
52
|
+
# don't send probes to our device
|
53
|
+
elsif ip == @ctx.iface.ip
|
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
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
# Each Discovery::Agent::Base derived class should implement this method.
|
67
|
+
def get_probe( ip )
|
68
|
+
Logger.warn "#{self.class.name}#get_probe not implemented!"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,44 @@
|
|
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
|
+
# Send a broadcast ping trying to filling the ARP table.
|
15
|
+
module BetterCap
|
16
|
+
module Discovery
|
17
|
+
module Agents
|
18
|
+
# Class responsible to do a ping-sweep on the network.
|
19
|
+
class Icmp
|
20
|
+
# Create a thread which will perform a ping-sweep on the network in order
|
21
|
+
# to populate the ARP cache with active targets.
|
22
|
+
def initialize( ctx, address = nil )
|
23
|
+
Firewalls::Base.get.enable_icmp_bcast(true)
|
24
|
+
|
25
|
+
# TODO: Use the real broadcast address for this network.
|
26
|
+
3.times do
|
27
|
+
pkt = PacketFu::ICMPPacket.new
|
28
|
+
|
29
|
+
pkt.eth_saddr = ctx.iface.mac
|
30
|
+
pkt.eth_daddr = 'ff:ff:ff:ff:ff:ff'
|
31
|
+
pkt.ip_saddr = ctx.iface.ip
|
32
|
+
pkt.ip_daddr = '255.255.255.255'
|
33
|
+
pkt.icmp_type = 8
|
34
|
+
pkt.icmp_code = 0
|
35
|
+
pkt.payload = "ABCD"
|
36
|
+
pkt.recalc
|
37
|
+
|
38
|
+
ctx.packets.push(pkt)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,30 @@
|
|
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
|
+
# Send UDP probes trying to filling the ARP table.
|
15
|
+
module BetterCap
|
16
|
+
module Discovery
|
17
|
+
module Agents
|
18
|
+
# Class responsible to send UDP probe packets to each possible IP on the network.
|
19
|
+
class Udp < Discovery::Agents::Base
|
20
|
+
private
|
21
|
+
|
22
|
+
# Build an UDP packet for the specified +ip+ address.
|
23
|
+
def get_probe( ip )
|
24
|
+
# send dummy udp packet, just to fill ARP table
|
25
|
+
[ ip.to_s, 137, "\x10\x12\x85\x00\x00" ]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,128 @@
|
|
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
|
+
module BetterCap
|
14
|
+
module Discovery
|
15
|
+
# Class responsible to actively discover targets on the network.
|
16
|
+
class Thread
|
17
|
+
# Initialize the class using the +ctx+ BetterCap::Context instance.
|
18
|
+
def initialize( ctx )
|
19
|
+
@ctx = ctx
|
20
|
+
@running = false
|
21
|
+
@thread = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# Start the active network discovery thread.
|
25
|
+
def start
|
26
|
+
@running = true
|
27
|
+
@thread = ::Thread.new { worker }
|
28
|
+
|
29
|
+
if @ctx.options.core.discovery?
|
30
|
+
###Logger.info "[#{'DISCOVERY'.green}] Targeting the whole subnet #{@ctx.iface.network.to_range} ..."
|
31
|
+
# give some time to the discovery thread to spawn its workers,
|
32
|
+
# this will prevent 'Too many open files' errors to delay host
|
33
|
+
# discovery.
|
34
|
+
sleep(1.5)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Stop the active network discovery thread.
|
39
|
+
def stop
|
40
|
+
@running = false
|
41
|
+
if @thread != nil
|
42
|
+
begin
|
43
|
+
@thread.exit
|
44
|
+
rescue
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
# Return true if the +list+ of targets includes +target+.
|
52
|
+
def list_include_target?( list, target )
|
53
|
+
list.each do |t|
|
54
|
+
if t.equals?(target.ip, target.mac)
|
55
|
+
return true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
61
|
+
# Print informations about new and lost targets.
|
62
|
+
def print_differences( prev )
|
63
|
+
diff = { :new => [], :lost => [] }
|
64
|
+
|
65
|
+
@ctx.targets.each do |target|
|
66
|
+
unless list_include_target?( prev, target )
|
67
|
+
diff[:new] << target
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
prev.each do |target|
|
72
|
+
unless list_include_target?( @ctx.targets, target )
|
73
|
+
diff[:lost] << target
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
unless diff[:new].empty? and diff[:lost].empty?
|
78
|
+
if diff[:new].empty?
|
79
|
+
snew = ""
|
80
|
+
else
|
81
|
+
snew = "Acquired #{diff[:new].size} new target#{diff[:new].size > 1 ? "s" : ""}"
|
82
|
+
end
|
83
|
+
|
84
|
+
if diff[:lost].empty?
|
85
|
+
slost = ""
|
86
|
+
else
|
87
|
+
slost = "#{snew.empty?? 'L' : ', l'}ost #{diff[:lost].size} target#{diff[:lost].size > 1 ? "s" : ""}"
|
88
|
+
end
|
89
|
+
|
90
|
+
Logger.info "#{snew}#{slost} :"
|
91
|
+
|
92
|
+
msg = "\n"
|
93
|
+
diff[:new].each do |target|
|
94
|
+
msg += " [#{'NEW'.green}] #{target.to_s(false)}\n"
|
95
|
+
end
|
96
|
+
diff[:lost].each do |target|
|
97
|
+
msg += " [#{'LOST'.red}] #{target.to_s(false)}\n"
|
98
|
+
end
|
99
|
+
msg += "\n"
|
100
|
+
Logger.raw msg
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# This method implements the main discovery logic, it will be executed within
|
105
|
+
# the spawned thread.
|
106
|
+
def worker
|
107
|
+
Logger.debug( 'Network discovery thread started.' ) if @ctx.options.core.discovery?
|
108
|
+
|
109
|
+
prev = []
|
110
|
+
while @running
|
111
|
+
# No targets specified.
|
112
|
+
if @ctx.options.core.targets.nil?
|
113
|
+
@ctx.targets = Network.get_alive_targets(@ctx).sort_by {
|
114
|
+
|t| t.sortable_ip
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
print_differences( prev ) if @ctx.options.core.discovery?
|
119
|
+
|
120
|
+
prev = @ctx.targets
|
121
|
+
|
122
|
+
@ctx.memory.optimize!
|
123
|
+
sleep(1) if @ctx.options.core.discovery?
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,16 @@
|
|
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
|
+
module BetterCap
|
14
|
+
# Class used to distinghuish between handled and unhandled exceptions.
|
15
|
+
class Error < StandardError; end
|
16
|
+
end
|