bettercap 1.1.10 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/TODO.md +8 -7
- data/bin/bettercap +8 -2
- data/lib/bettercap.rb +5 -4
- data/lib/bettercap/context.rb +54 -8
- data/lib/bettercap/discovery/agents/arp.rb +17 -4
- data/lib/bettercap/discovery/agents/base.rb +16 -52
- data/lib/bettercap/discovery/agents/icmp.rb +25 -17
- data/lib/bettercap/discovery/agents/udp.rb +9 -20
- data/lib/bettercap/discovery/{discovery.rb → thread.rb} +10 -9
- data/lib/bettercap/error.rb +1 -2
- data/lib/bettercap/factories/{firewall_factory.rb → firewall.rb} +11 -7
- data/lib/bettercap/factories/{parser_factory.rb → parser.rb} +13 -3
- data/lib/bettercap/factories/{spoofer_factory.rb → spoofer.rb} +10 -3
- data/lib/bettercap/firewalls/base.rb +76 -0
- data/lib/bettercap/firewalls/linux.rb +26 -16
- data/lib/bettercap/firewalls/osx.rb +22 -13
- data/lib/bettercap/firewalls/redirection.rb +15 -1
- data/lib/bettercap/httpd/server.rb +5 -0
- data/lib/bettercap/logger.rb +29 -8
- data/lib/bettercap/network.rb +105 -105
- data/lib/bettercap/options.rb +99 -41
- data/lib/bettercap/packet_queue.rb +92 -0
- data/lib/bettercap/proxy/certstore.rb +49 -43
- data/lib/bettercap/proxy/module.rb +4 -2
- data/lib/bettercap/proxy/proxy.rb +7 -2
- data/lib/bettercap/proxy/request.rb +28 -16
- data/lib/bettercap/proxy/response.rb +23 -2
- data/lib/bettercap/proxy/stream_logger.rb +6 -0
- data/lib/bettercap/proxy/streamer.rb +13 -5
- data/lib/bettercap/proxy/thread_pool.rb +6 -14
- data/lib/bettercap/shell.rb +5 -3
- data/lib/bettercap/sniffer/parsers/base.rb +7 -1
- data/lib/bettercap/sniffer/parsers/custom.rb +6 -1
- data/lib/bettercap/sniffer/parsers/ftp.rb +8 -5
- data/lib/bettercap/sniffer/parsers/httpauth.rb +4 -1
- data/lib/bettercap/sniffer/parsers/https.rb +4 -1
- data/lib/bettercap/sniffer/parsers/irc.rb +8 -5
- data/lib/bettercap/sniffer/parsers/mail.rb +8 -5
- data/lib/bettercap/sniffer/parsers/ntlmss.rb +21 -18
- data/lib/bettercap/sniffer/parsers/post.rb +4 -1
- data/lib/bettercap/sniffer/parsers/url.rb +4 -1
- data/lib/bettercap/sniffer/sniffer.rb +7 -3
- data/lib/bettercap/spoofers/arp.rb +69 -94
- data/lib/bettercap/spoofers/base.rb +132 -0
- data/lib/bettercap/spoofers/icmp.rb +200 -0
- data/lib/bettercap/spoofers/none.rb +8 -2
- data/lib/bettercap/target.rb +117 -90
- data/lib/bettercap/update_checker.rb +6 -0
- data/lib/bettercap/version.rb +3 -1
- metadata +24 -8
- data/lib/bettercap/base/ifirewall.rb +0 -46
- data/lib/bettercap/base/ispoofer.rb +0 -32
@@ -11,9 +11,10 @@ This project is released under the GPL 3 license.
|
|
11
11
|
=end
|
12
12
|
require 'thread'
|
13
13
|
|
14
|
-
# Tnx to Puma ThreadPool!
|
15
14
|
module BetterCap
|
16
15
|
module Proxy
|
16
|
+
# Thread pool class used by the BetterCap::Proxy::Proxy.
|
17
|
+
# Tnx to Puma ThreadPool!
|
17
18
|
class ThreadPool
|
18
19
|
|
19
20
|
# Maintain a minimum of +min+ and maximum of +max+ threads
|
@@ -21,7 +22,6 @@ class ThreadPool
|
|
21
22
|
#
|
22
23
|
# The block passed is the work that will be performed in each
|
23
24
|
# thread.
|
24
|
-
#
|
25
25
|
def initialize(min, max, *extra, &block)
|
26
26
|
@not_empty = ConditionVariable.new
|
27
27
|
@not_full = ConditionVariable.new
|
@@ -46,12 +46,10 @@ class ThreadPool
|
|
46
46
|
@mutex.synchronize do
|
47
47
|
@min.times { spawn_thread }
|
48
48
|
end
|
49
|
-
|
50
|
-
@clean_thread_locals = false
|
51
49
|
end
|
52
50
|
|
53
|
-
|
54
|
-
|
51
|
+
# Number of spawned threads in the pool.
|
52
|
+
attr_reader :spawned
|
55
53
|
|
56
54
|
# How many objects have yet to be processed by the pool?
|
57
55
|
#
|
@@ -104,12 +102,6 @@ class ThreadPool
|
|
104
102
|
|
105
103
|
break unless continue
|
106
104
|
|
107
|
-
if @clean_thread_locals
|
108
|
-
Thread.current.keys.each do |key|
|
109
|
-
Thread.current[key] = nil unless key == :__recursive_key__
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
105
|
begin
|
114
106
|
block.call(work, *extra)
|
115
107
|
rescue Exception
|
@@ -184,7 +176,7 @@ class ThreadPool
|
|
184
176
|
|
185
177
|
# Tell all threads in the pool to exit and wait for them to finish.
|
186
178
|
#
|
187
|
-
def shutdown
|
179
|
+
def shutdown( join_threads = true )
|
188
180
|
threads = @mutex.synchronize do
|
189
181
|
@shutdown = true
|
190
182
|
@not_empty.broadcast
|
@@ -193,7 +185,7 @@ class ThreadPool
|
|
193
185
|
@workers.dup
|
194
186
|
end
|
195
187
|
|
196
|
-
threads.each(&:join)
|
188
|
+
threads.each(&:join) if join_threads
|
197
189
|
|
198
190
|
@spawned = 0
|
199
191
|
@workers = []
|
data/lib/bettercap/shell.rb
CHANGED
@@ -8,10 +8,11 @@ This project is released under the GPL 3 license.
|
|
8
8
|
require 'bettercap/error'
|
9
9
|
|
10
10
|
module BetterCap
|
11
|
+
# Class responsible of executing various shell commands.
|
11
12
|
module Shell
|
12
13
|
class << self
|
13
|
-
|
14
|
-
#
|
14
|
+
# Execute +command+ and return its output.
|
15
|
+
# Raise +BetterCap::Error+ if the return code is not 0.
|
15
16
|
def execute(command)
|
16
17
|
r = ''
|
17
18
|
10.times do
|
@@ -29,14 +30,15 @@ module Shell
|
|
29
30
|
r
|
30
31
|
end
|
31
32
|
|
33
|
+
# Get the +iface+ network interface configuration.
|
32
34
|
def ifconfig(iface = '')
|
33
35
|
self.execute( "LANG=en && ifconfig #{iface}" )
|
34
36
|
end
|
35
37
|
|
38
|
+
# Get the ARP table cached on this computer.
|
36
39
|
def arp
|
37
40
|
self.execute( 'LANG=en && arp -a -n' )
|
38
41
|
end
|
39
|
-
|
40
42
|
end
|
41
43
|
end
|
42
44
|
end
|
@@ -10,12 +10,17 @@ This project is released under the GPL 3 license.
|
|
10
10
|
|
11
11
|
=end
|
12
12
|
module BetterCap
|
13
|
-
|
13
|
+
module Parsers
|
14
|
+
# Base class for BetterCap::Parsers.
|
15
|
+
class Base
|
16
|
+
# Initialize this parser.
|
14
17
|
def initialize
|
15
18
|
@filters = []
|
16
19
|
@name = 'BASE'
|
17
20
|
end
|
18
21
|
|
22
|
+
# This method will be called from the BetterCap::Sniffer for each
|
23
|
+
# incoming packet ( +pkt ) and will apply the parser filter to it.
|
19
24
|
def on_packet( pkt )
|
20
25
|
s = pkt.to_s
|
21
26
|
@filters.each do |filter|
|
@@ -26,3 +31,4 @@ class BaseParser
|
|
26
31
|
end
|
27
32
|
end
|
28
33
|
end
|
34
|
+
end
|
@@ -12,10 +12,15 @@ This project is released under the GPL 3 license.
|
|
12
12
|
require 'bettercap/sniffer/parsers/base'
|
13
13
|
|
14
14
|
module BetterCap
|
15
|
-
|
15
|
+
module Parsers
|
16
|
+
# Parser used when the "--custom-parser EXPRESSION" command line
|
17
|
+
# argument is specified.
|
18
|
+
class Custom < Base
|
19
|
+
# Initialize the parser given the +filter+ Regexp object.
|
16
20
|
def initialize( filter )
|
17
21
|
@filters = [ filter ]
|
18
22
|
@name = 'DATA'
|
19
23
|
end
|
20
24
|
end
|
21
25
|
end
|
26
|
+
end
|
@@ -12,10 +12,13 @@ This project is released under the GPL 3 license.
|
|
12
12
|
require 'bettercap/sniffer/parsers/base'
|
13
13
|
|
14
14
|
module BetterCap
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
module Parsers
|
16
|
+
# FTP authentication parser.
|
17
|
+
class Ftp < Base
|
18
|
+
def initialize
|
19
|
+
@filters = [ /(USER|PASS)\s+.+/ ]
|
20
|
+
@name = 'FTP'
|
21
|
+
end
|
22
|
+
end
|
20
23
|
end
|
21
24
|
end
|
@@ -14,7 +14,9 @@ require 'colorize'
|
|
14
14
|
require 'base64'
|
15
15
|
|
16
16
|
module BetterCap
|
17
|
-
|
17
|
+
module Parsers
|
18
|
+
# HTTP basic and digest authentication parser.
|
19
|
+
class Httpauth < Base
|
18
20
|
def on_packet( pkt )
|
19
21
|
lines = pkt.to_s.split("\n")
|
20
22
|
hostname = nil
|
@@ -41,3 +43,4 @@ class HttpauthParser < BaseParser
|
|
41
43
|
end
|
42
44
|
end
|
43
45
|
end
|
46
|
+
end
|
@@ -14,7 +14,9 @@ require 'colorize'
|
|
14
14
|
require 'resolv'
|
15
15
|
|
16
16
|
module BetterCap
|
17
|
-
|
17
|
+
module Parsers
|
18
|
+
# HTTPS connections parser.
|
19
|
+
class Https < Base
|
18
20
|
@@prev = nil
|
19
21
|
|
20
22
|
def on_packet( pkt )
|
@@ -39,3 +41,4 @@ class HttpsParser < BaseParser
|
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
44
|
+
end
|
@@ -12,10 +12,13 @@ This project is released under the GPL 3 license.
|
|
12
12
|
require 'bettercap/sniffer/parsers/base'
|
13
13
|
|
14
14
|
module BetterCap
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
module Parsers
|
16
|
+
# IRC protocol parser.
|
17
|
+
class Irc < Base
|
18
|
+
def initialize
|
19
|
+
@filters = [ /NICK\s+.+/, /NS IDENTIFY\s+.+/, /nickserv :identify\s+.+/ ]
|
20
|
+
@name = 'IRC'
|
21
|
+
end
|
22
|
+
end
|
20
23
|
end
|
21
24
|
end
|
@@ -12,10 +12,13 @@ This project is released under the GPL 3 license.
|
|
12
12
|
require 'bettercap/sniffer/parsers/base'
|
13
13
|
|
14
14
|
module BetterCap
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
module Parsers
|
16
|
+
# POP/IMAP authentication parser.
|
17
|
+
class Mail < Base
|
18
|
+
def initialize
|
19
|
+
@filters = [ /(\d+ )?(auth|authenticate) ([a-z\-_0-9]+)/i ]
|
20
|
+
@name = 'MAIL'
|
21
|
+
end
|
22
|
+
end
|
20
23
|
end
|
21
24
|
end
|
@@ -13,26 +13,29 @@ require 'bettercap/sniffer/parsers/base'
|
|
13
13
|
require 'colorize'
|
14
14
|
|
15
15
|
module BetterCap
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
16
|
+
module Parsers
|
17
|
+
# NTLMSS traffic parser.
|
18
|
+
class Ntlmss < Base
|
19
|
+
# Convert binary +data+ into human readable hexadecimal representation.
|
20
|
+
def bin2hex( data )
|
21
|
+
hex = ''
|
22
|
+
data.each_byte do |byte|
|
23
|
+
if /[[:print:]]/ === byte.chr
|
24
|
+
hex += byte.chr
|
25
|
+
else
|
26
|
+
hex += "\\x" + byte.to_s(16)
|
27
|
+
end
|
28
28
|
end
|
29
|
+
hex
|
30
|
+
end
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
32
|
+
def on_packet( pkt )
|
33
|
+
s = pkt.to_s
|
34
|
+
if s =~ /NTLMSSP\x00\x03\x00\x00\x00.+/
|
35
|
+
# TODO: Parse NTLMSSP packet.
|
36
|
+
StreamLogger.log_raw( pkt, 'NTLMSS', bin2hex( pkt.payload ) )
|
36
37
|
end
|
38
|
+
end
|
39
|
+
end
|
37
40
|
end
|
38
41
|
end
|
@@ -13,7 +13,9 @@ require 'bettercap/sniffer/parsers/base'
|
|
13
13
|
require 'colorize'
|
14
14
|
|
15
15
|
module BetterCap
|
16
|
-
|
16
|
+
module Parsers
|
17
|
+
# HTTP POST requests parser.
|
18
|
+
class Post < Base
|
17
19
|
def on_packet( pkt )
|
18
20
|
s = pkt.to_s
|
19
21
|
if s =~ /POST\s+[^\s]+\s+HTTP.+/
|
@@ -22,3 +24,4 @@ class PostParser < BaseParser
|
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
27
|
+
end
|
@@ -13,7 +13,9 @@ require 'bettercap/sniffer/parsers/base'
|
|
13
13
|
require 'colorize'
|
14
14
|
|
15
15
|
module BetterCap
|
16
|
-
|
16
|
+
module Parsers
|
17
|
+
# HTTP GET requests parser.
|
18
|
+
class Url < Base
|
17
19
|
def on_packet( pkt )
|
18
20
|
s = pkt.to_s
|
19
21
|
if s =~ /GET\s+([^\s]+)\s+HTTP.+Host:\s+([^\s]+).+/m
|
@@ -26,3 +28,4 @@ class UrlParser < BaseParser
|
|
26
28
|
end
|
27
29
|
end
|
28
30
|
end
|
31
|
+
end
|
@@ -10,11 +10,12 @@ This project is released under the GPL 3 license.
|
|
10
10
|
|
11
11
|
=end
|
12
12
|
require 'bettercap/logger'
|
13
|
-
require 'bettercap/factories/parser_factory'
|
14
13
|
require 'colorize'
|
15
14
|
require 'packetfu'
|
16
15
|
|
17
16
|
module BetterCap
|
17
|
+
# Class responsible of loading BetterCap::Parsers instances and performing
|
18
|
+
# network packet sniffing and dumping.
|
18
19
|
class Sniffer
|
19
20
|
include PacketFu
|
20
21
|
|
@@ -23,6 +24,9 @@ class Sniffer
|
|
23
24
|
@@pcap = nil
|
24
25
|
@@cap = nil
|
25
26
|
|
27
|
+
# Start a new thread that will sniff packets from the network and pass
|
28
|
+
# each one of them to the BetterCap::Parsers instances loaded inside the
|
29
|
+
# +ctx+ BetterCap::Context instance.
|
26
30
|
def self.start( ctx )
|
27
31
|
Thread.new do
|
28
32
|
Logger.info 'Starting sniffer ...'
|
@@ -94,9 +98,9 @@ class Sniffer
|
|
94
98
|
end
|
95
99
|
|
96
100
|
if @@ctx.options.custom_parser.nil?
|
97
|
-
@@parsers =
|
101
|
+
@@parsers = Factories::Parser.load_by_names @@ctx.options.parsers
|
98
102
|
else
|
99
|
-
@@parsers =
|
103
|
+
@@parsers = Factories::Parser.load_custom @@ctx.options.custom_parser
|
100
104
|
end
|
101
105
|
|
102
106
|
@@cap = Capture.new(
|
@@ -9,15 +9,18 @@ Blog : http://www.evilsocket.net/
|
|
9
9
|
This project is released under the GPL 3 license.
|
10
10
|
|
11
11
|
=end
|
12
|
+
require 'bettercap/spoofers/base'
|
12
13
|
require 'bettercap/error'
|
13
14
|
require 'bettercap/context'
|
14
|
-
require 'bettercap/base/ispoofer'
|
15
15
|
require 'bettercap/network'
|
16
16
|
require 'bettercap/logger'
|
17
17
|
require 'colorize'
|
18
18
|
|
19
19
|
module BetterCap
|
20
|
-
|
20
|
+
module Spoofers
|
21
|
+
# This class is responsible of performing ARP spoofing on the network.
|
22
|
+
class Arp < Base
|
23
|
+
# Initialize the BetterCap::Spoofers::Arp object.
|
21
24
|
def initialize
|
22
25
|
@ctx = Context.get
|
23
26
|
@gateway = nil
|
@@ -27,16 +30,12 @@ class ArpSpoofer < ISpoofer
|
|
27
30
|
@capture = nil
|
28
31
|
@running = false
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
hw = Network.get_hw_address( @ctx.ifconfig, @ctx.gateway )
|
33
|
-
raise BetterCap::Error, "Couldn't determine router MAC" if hw.nil?
|
34
|
-
|
35
|
-
@gateway = Target.new( @ctx.gateway, hw )
|
36
|
-
|
37
|
-
Logger.info " #{@gateway}"
|
33
|
+
update_gateway!
|
38
34
|
end
|
39
35
|
|
36
|
+
# Send a spoofed ARP reply to the target identified by the +daddr+ IP address
|
37
|
+
# and +dmac+ MAC address, spoofing the +saddr+ IP address and +smac+ MAC
|
38
|
+
# address as the source device.
|
40
39
|
def send_spoofed_packet( saddr, smac, daddr, dmac )
|
41
40
|
pkt = PacketFu::ARPPacket.new
|
42
41
|
pkt.eth_saddr = smac
|
@@ -47,9 +46,10 @@ class ArpSpoofer < ISpoofer
|
|
47
46
|
pkt.arp_daddr_ip = daddr
|
48
47
|
pkt.arp_opcode = 2
|
49
48
|
|
50
|
-
|
49
|
+
@ctx.packets.push(pkt)
|
51
50
|
end
|
52
51
|
|
52
|
+
# Start the ARP spoofing.
|
53
53
|
def start
|
54
54
|
Logger.info "Starting ARP spoofer ( #{@ctx.options.half_duplex ? 'Half' : 'Full'} Duplex ) ..."
|
55
55
|
|
@@ -58,89 +58,11 @@ class ArpSpoofer < ISpoofer
|
|
58
58
|
|
59
59
|
@ctx.firewall.enable_forwarding(true) unless @forwarding
|
60
60
|
|
61
|
-
@sniff_thread = Thread.new
|
62
|
-
|
63
|
-
begin
|
64
|
-
@capture = PacketFu::Capture.new(
|
65
|
-
iface: @ctx.options.iface,
|
66
|
-
filter: 'arp',
|
67
|
-
start: true
|
68
|
-
)
|
69
|
-
rescue Exception => e
|
70
|
-
Logger.error e.message
|
71
|
-
end
|
72
|
-
|
73
|
-
@capture.stream.each do |p|
|
74
|
-
begin
|
75
|
-
pkt = PacketFu::Packet.parse p
|
76
|
-
# we're only interested in 'who-has' packets
|
77
|
-
if pkt.arp_opcode == 1 and pkt.arp_dst_mac.to_s == '00:00:00:00:00:00'
|
78
|
-
is_from_us = ( pkt.arp_src_ip.to_s == @ctx.ifconfig[:ip_saddr] )
|
79
|
-
unless is_from_us
|
80
|
-
Logger.info "[ARP] #{pkt.arp_src_ip.to_s} is asking who #{pkt.arp_dst_ip.to_s} is."
|
81
|
-
|
82
|
-
send_spoofed_packet pkt.arp_dst_ip.to_s, @ctx.ifconfig[:eth_saddr], pkt.arp_src_ip.to_s, pkt.arp_src_mac.to_s
|
83
|
-
end
|
84
|
-
end
|
85
|
-
rescue Exception => e
|
86
|
-
Logger.error e.message
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
@spoof_thread = Thread.new do
|
92
|
-
prev_size = @ctx.targets.size
|
93
|
-
loop do
|
94
|
-
if not @running
|
95
|
-
Logger.debug 'Stopping spoofing thread ...'
|
96
|
-
Thread.exit
|
97
|
-
break
|
98
|
-
end
|
99
|
-
|
100
|
-
size = @ctx.targets.size
|
101
|
-
|
102
|
-
if size > prev_size
|
103
|
-
Logger.warn "Aquired #{size - prev_size} new targets."
|
104
|
-
elsif size < prev_size
|
105
|
-
Logger.warn "Lost #{prev_size - size} targets."
|
106
|
-
end
|
107
|
-
|
108
|
-
Logger.debug "Spoofing #{@ctx.targets.size} targets ..."
|
109
|
-
|
110
|
-
@ctx.targets.each do |target|
|
111
|
-
# targets could change, update mac addresses if needed
|
112
|
-
if target.mac.nil?
|
113
|
-
hw = Network.get_hw_address( @ctx.ifconfig, target.ip )
|
114
|
-
if hw.nil?
|
115
|
-
Logger.warn "Couldn't determine target #{ip} MAC!"
|
116
|
-
next
|
117
|
-
else
|
118
|
-
Logger.info " Target MAC : #{hw}"
|
119
|
-
target.mac = hw
|
120
|
-
end
|
121
|
-
# target was specified by MAC address
|
122
|
-
elsif target.ip_refresh
|
123
|
-
ip = Network.get_ip_address( @ctx, target.mac )
|
124
|
-
if ip.nil?
|
125
|
-
Logger.warn "Couldn't determine target #{target.mac} IP!"
|
126
|
-
next
|
127
|
-
else
|
128
|
-
Logger.info "Target #{target.mac} IP : #{ip}" if target.ip.nil? or target.ip != ip
|
129
|
-
target.ip = ip
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
send_spoofed_packet( @gateway.ip, @ctx.ifconfig[:eth_saddr], target.ip, target.mac )
|
134
|
-
send_spoofed_packet( target.ip, @ctx.ifconfig[:eth_saddr], @gateway.ip, @gateway.mac ) unless @ctx.options.half_duplex
|
135
|
-
end
|
136
|
-
|
137
|
-
prev_size = @ctx.targets.size
|
138
|
-
|
139
|
-
sleep(1)
|
140
|
-
end
|
141
|
-
end
|
61
|
+
@sniff_thread = Thread.new { arp_watcher }
|
62
|
+
@spoof_thread = Thread.new { arp_spoofer }
|
142
63
|
end
|
143
64
|
|
65
|
+
# Stop the ARP spoofing, reset firewall state and restore targets ARP table.
|
144
66
|
def stop
|
145
67
|
raise 'ARP spoofer is not running' unless @running
|
146
68
|
|
@@ -158,14 +80,67 @@ class ArpSpoofer < ISpoofer
|
|
158
80
|
Logger.info "Restoring ARP table of #{@ctx.targets.size} targets ..."
|
159
81
|
|
160
82
|
@ctx.targets.each do |target|
|
161
|
-
unless target.mac.nil?
|
83
|
+
unless target.ip.nil? or target.mac.nil?
|
162
84
|
begin
|
163
85
|
send_spoofed_packet( @gateway.ip, @gateway.mac, target.ip, target.mac )
|
164
86
|
send_spoofed_packet( target.ip, target.mac, @gateway.ip, @gateway.mac ) unless @ctx.options.half_duplex
|
165
87
|
rescue; end
|
166
88
|
end
|
167
89
|
end
|
168
|
-
sleep 1
|
169
90
|
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def update_targets!
|
95
|
+
@ctx.targets.each do |target|
|
96
|
+
# targets could change, update mac addresses if needed
|
97
|
+
if target.mac.nil?
|
98
|
+
hw = Network.get_hw_address( @ctx.ifconfig, target.ip )
|
99
|
+
if hw.nil?
|
100
|
+
Logger.warn "Couldn't determine target #{ip} MAC!"
|
101
|
+
next
|
102
|
+
else
|
103
|
+
Logger.info " Target MAC : #{hw}"
|
104
|
+
target.mac = hw
|
105
|
+
end
|
106
|
+
# target was specified by MAC address
|
107
|
+
elsif target.ip_refresh
|
108
|
+
ip = Network.get_ip_address( @ctx, target.mac )
|
109
|
+
if ip.nil?
|
110
|
+
Logger.warn "Couldn't determine target #{target.mac} IP!"
|
111
|
+
next
|
112
|
+
else
|
113
|
+
Logger.info "Target #{target.mac} IP : #{ip}" if target.ip.nil? or target.ip != ip
|
114
|
+
target.ip = ip
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def arp_spoofer
|
121
|
+
spoof_loop(1) { |target|
|
122
|
+
unless target.ip.nil? or target.mac.nil?
|
123
|
+
send_spoofed_packet( @gateway.ip, @ctx.ifconfig[:eth_saddr], target.ip, target.mac )
|
124
|
+
send_spoofed_packet( target.ip, @ctx.ifconfig[:eth_saddr], @gateway.ip, @gateway.mac ) unless @ctx.options.half_duplex
|
125
|
+
end
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
def arp_watcher
|
130
|
+
Logger.info 'ARP watcher started ...'
|
131
|
+
|
132
|
+
sniff_packets('arp') { |pkt|
|
133
|
+
# we're only interested in 'who-has' packets
|
134
|
+
if pkt.arp_opcode == 1 and pkt.arp_dst_mac.to_s == '00:00:00:00:00:00'
|
135
|
+
is_from_us = ( pkt.arp_src_ip.to_s == @ctx.ifconfig[:ip_saddr] )
|
136
|
+
unless is_from_us
|
137
|
+
Logger.info "[ARP] #{pkt.arp_src_ip.to_s} is asking who #{pkt.arp_dst_ip.to_s} is."
|
138
|
+
|
139
|
+
send_spoofed_packet pkt.arp_dst_ip.to_s, @ctx.ifconfig[:eth_saddr], pkt.arp_src_ip.to_s, pkt.arp_src_mac.to_s
|
140
|
+
end
|
141
|
+
end
|
142
|
+
}
|
143
|
+
end
|
144
|
+
end
|
170
145
|
end
|
171
146
|
end
|