bettercap 1.1.7 → 1.1.8

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.
@@ -42,9 +42,6 @@ class ThreadPool
42
42
 
43
43
  @workers = []
44
44
 
45
- @auto_trim = nil
46
- @reaper = nil
47
-
48
45
  @mutex.synchronize do
49
46
  @min.times { spawn_thread }
50
47
  end
@@ -184,64 +181,6 @@ class ThreadPool
184
181
  end
185
182
  end
186
183
 
187
- class AutoTrim
188
- def initialize(pool, timeout)
189
- @pool = pool
190
- @timeout = timeout
191
- @running = false
192
- end
193
-
194
- def start!
195
- @running = true
196
-
197
- @thread = Thread.new do
198
- while @running
199
- @pool.trim
200
- sleep @timeout
201
- end
202
- end
203
- end
204
-
205
- def stop
206
- @running = false
207
- @thread.wakeup
208
- end
209
- end
210
-
211
- def auto_trim!(timeout=5)
212
- @auto_trim = AutoTrim.new(self, timeout)
213
- @auto_trim.start!
214
- end
215
-
216
- class Reaper
217
- def initialize(pool, timeout)
218
- @pool = pool
219
- @timeout = timeout
220
- @running = false
221
- end
222
-
223
- def start!
224
- @running = true
225
-
226
- @thread = Thread.new do
227
- while @running
228
- @pool.reap
229
- sleep @timeout
230
- end
231
- end
232
- end
233
-
234
- def stop
235
- @running = false
236
- @thread.wakeup
237
- end
238
- end
239
-
240
- def auto_reap!(timeout=5)
241
- @reaper = Reaper.new(self, timeout)
242
- @reaper.start!
243
- end
244
-
245
184
  # Tell all threads in the pool to exit and wait for them to finish.
246
185
  #
247
186
  def shutdown
@@ -249,9 +188,6 @@ class ThreadPool
249
188
  @shutdown = true
250
189
  @not_empty.broadcast
251
190
  @not_full.broadcast
252
-
253
- @auto_trim.stop if @auto_trim
254
- @reaper.stop if @reaper
255
191
  # dup workers so that we join them all safely
256
192
  @workers.dup
257
193
  end
@@ -18,11 +18,17 @@ class BaseParser
18
18
  @name = 'BASE'
19
19
  end
20
20
 
21
+ def addr2s( addr )
22
+ target = Context.get.find_target addr, nil
23
+ return target.to_s_compact unless target.nil?
24
+ addr
25
+ end
26
+
21
27
  def on_packet( pkt )
22
28
  s = pkt.to_s
23
29
  @filters.each do |filter|
24
30
  if s =~ filter
25
- Logger.write "[#{pkt.ip_saddr}:#{pkt.tcp_src} > #{pkt.ip_daddr}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
31
+ Logger.write "[#{addr2s(pkt.ip_saddr)}:#{pkt.tcp_src} > #{addr2s(pkt.ip_daddr)}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
26
32
  "[#{@name}] ".green +
27
33
  pkt.payload.strip.yellow
28
34
  end
@@ -22,7 +22,7 @@ class HttpauthParser < BaseParser
22
22
  lines.each do |line|
23
23
  if line =~ /[A-Z]+\s+(\/[^\s]+)\s+HTTP\/\d\.\d/
24
24
  path = $1
25
-
25
+
26
26
  elsif line =~ /Host:\s*([^\s]+)/i
27
27
  hostname = $1
28
28
 
@@ -31,15 +31,14 @@ class HttpauthParser < BaseParser
31
31
  decoded = Base64.decode64(encoded)
32
32
  user, pass = decoded.split(':')
33
33
 
34
- Logger.write "[#{pkt.ip_saddr}:#{pkt.tcp_src} > #{pkt.ip_daddr}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
34
+ Logger.write "[#{addr2s(pkt.ip_saddr)}:#{pkt.tcp_src} > #{addr2s(pkt.ip_daddr)}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
35
35
  '[HTTP BASIC AUTH]'.green + " http://#{hostname}#{path} - username=#{user} password=#{pass}".yellow
36
-
36
+
37
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}] " +
38
+ Logger.write "[#{addr2s(pkt.ip_saddr)}:#{pkt.tcp_src} > #{addr2s(pkt.ip_daddr)}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
39
39
  '[HTTP DIGEST AUTH]'.green + " http://#{hostname}#{path}\n#{$1}".yellow
40
40
 
41
41
  end
42
42
  end
43
43
  end
44
44
  end
45
-
@@ -28,7 +28,7 @@ class HttpsParser < BaseParser
28
28
  end
29
29
 
30
30
  if @@prev.nil? or @@prev != hostname
31
- Logger.write "[#{pkt.ip_saddr}:#{pkt.tcp_src} > #{pkt.ip_daddr}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
31
+ Logger.write "[#{addr2s(pkt.ip_saddr)}:#{pkt.tcp_src} > #{addr2s(pkt.ip_daddr)}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
32
32
  '[HTTPS] '.green +
33
33
  "https://#{hostname}/".yellow
34
34
 
@@ -30,7 +30,7 @@ class NtlmssParser < BaseParser
30
30
  s = pkt.to_s
31
31
  if s =~ /NTLMSSP\x00\x03\x00\x00\x00.+/
32
32
  # TODO: Parse NTLMSSP packet.
33
- Logger.write "[#{pkt.ip_saddr} > #{pkt.ip_daddr} #{pkt.proto.last}] " +
33
+ Logger.write "[#{addr2s(pkt.ip_saddr)} > #{addr2s(pkt.ip_daddr)} #{pkt.proto.last}] " +
34
34
  '[NTLMSS] '.green +
35
35
  bin2hex( pkt.payload ).yellow
36
36
  end
@@ -16,7 +16,7 @@ class PostParser < BaseParser
16
16
  def on_packet( pkt )
17
17
  s = pkt.to_s
18
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}] " +
19
+ Logger.write "[#{addr2s(pkt.ip_saddr)}:#{pkt.tcp_src} > #{addr2s(pkt.ip_daddr)}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
20
20
  "[POST]\n".green +
21
21
  pkt.payload.strip.yellow
22
22
  end
@@ -19,7 +19,7 @@ class UrlParser < BaseParser
19
19
  host = $2
20
20
  url = $1
21
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}] " +
22
+ Logger.write "[#{addr2s(pkt.ip_saddr)}:#{pkt.tcp_src} > #{addr2s(pkt.ip_daddr)}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
23
23
  '[GET] '.green +
24
24
  "http://#{host}#{url}".yellow
25
25
  end
@@ -45,17 +45,17 @@ class Sniffer
45
45
  private
46
46
 
47
47
  def self.stream
48
- if @@ctx.options[:sniffer_src].nil?
48
+ if @@ctx.options.sniffer_src.nil?
49
49
  @@cap.stream
50
50
  else
51
- Logger.info "Reading packets from #{@@ctx.options[:sniffer_src]} ..."
51
+ Logger.info "Reading packets from #{@@ctx.options.sniffer_src} ..."
52
52
 
53
- PcapFile.file_to_array @@ctx.options[:sniffer_src]
53
+ PcapFile.file_to_array @@ctx.options.sniffer_src
54
54
  end
55
55
  end
56
56
 
57
57
  def self.skip_packet?( pkt )
58
- !@@ctx.options[:local] and
58
+ !@@ctx.options.local and
59
59
  ( pkt.ip_saddr == @@ctx.ifconfig[:ip_saddr] or
60
60
  pkt.ip_daddr == @@ctx.ifconfig[:ip_saddr] )
61
61
  end
@@ -73,7 +73,7 @@ class Sniffer
73
73
  def self.append_packet( p )
74
74
  begin
75
75
  @@pcap.array_to_file(
76
- filename: @@ctx.options[:sniffer_pcap],
76
+ filename: @@ctx.options.sniffer_pcap,
77
77
  array: [p],
78
78
  append: true ) unless @@pcap.nil?
79
79
  rescue Exception => e
@@ -84,16 +84,16 @@ class Sniffer
84
84
  def self.setup( ctx )
85
85
  @@ctx = ctx
86
86
 
87
- if !@@ctx.options[:sniffer_pcap].nil?
87
+ if !@@ctx.options.sniffer_pcap.nil?
88
88
  @@pcap = PcapFile.new
89
- Logger.warn "Saving packets to #{@@ctx.options[:sniffer_pcap]} ."
89
+ Logger.warn "Saving packets to #{@@ctx.options.sniffer_pcap} ."
90
90
  end
91
91
 
92
- @@parsers = ParserFactory.load_by_names @@ctx.options[:parsers]
92
+ @@parsers = ParserFactory.load_by_names @@ctx.options.parsers
93
93
 
94
94
  @@cap = Capture.new(
95
- iface: @@ctx.options[:iface],
96
- filter: @@ctx.options[:sniffer_filter],
95
+ iface: @@ctx.options.iface,
96
+ filter: @@ctx.options.sniffer_filter,
97
97
  start: true
98
98
  )
99
99
  end
@@ -51,35 +51,31 @@ class ArpSpoofer < ISpoofer
51
51
  end
52
52
 
53
53
  def start
54
- stop() unless @running == false
54
+ Logger.info "Starting ARP spoofer ( #{@ctx.options.half_duplex ? 'Half' : 'Full'} Duplex ) ..."
55
55
 
56
- Logger.info "Starting ARP spoofer ( #{@ctx.options[:half_duplex] ? 'Half' : 'Full'} Duplex ) ..."
57
-
58
- if @forwarding == false
59
- Logger.debug 'Enabling packet forwarding.'
56
+ stop() unless !@running
57
+ @running = true
60
58
 
61
- @ctx.firewall.enable_forwarding(true)
62
- end
59
+ @ctx.firewall.enable_forwarding(true) unless @forwarding
63
60
 
64
- @running = true
65
61
  @sniff_thread = Thread.new do
66
62
  Logger.info 'ARP watcher started ...'
67
63
  begin
68
- @capture = PacketFu::Capture.new(
69
- iface: @ctx.options[:iface],
70
- filter: 'arp',
71
- start: true
72
- )
64
+ @capture = PacketFu::Capture.new(
65
+ iface: @ctx.options.iface,
66
+ filter: 'arp',
67
+ start: true
68
+ )
73
69
  rescue Exception => e
74
70
  Logger.error e.message
75
71
  end
72
+
76
73
  @capture.stream.each do |p|
77
74
  begin
78
75
  pkt = PacketFu::Packet.parse p
79
76
  # we're only interested in 'who-has' packets
80
77
  if pkt.arp_opcode == 1 and pkt.arp_dst_mac.to_s == '00:00:00:00:00:00'
81
78
  is_from_us = ( pkt.arp_src_ip.to_s == @ctx.ifconfig[:ip_saddr] )
82
-
83
79
  if !is_from_us
84
80
  Logger.info "[ARP] #{pkt.arp_src_ip.to_s} is asking who #{pkt.arp_dst_ip.to_s} is."
85
81
 
@@ -122,13 +118,12 @@ class ArpSpoofer < ISpoofer
122
118
  next
123
119
  else
124
120
  Logger.info " Target MAC : #{hw}"
125
-
126
121
  target.mac = hw
127
122
  end
128
123
  end
129
124
 
130
125
  send_spoofed_packet( @ctx.gateway, @ctx.ifconfig[:eth_saddr], target.ip, target.mac )
131
- send_spoofed_packet( target.ip, @ctx.ifconfig[:eth_saddr], @ctx.gateway, @gw_hw ) unless @ctx.options[:half_duplex]
126
+ send_spoofed_packet( target.ip, @ctx.ifconfig[:eth_saddr], @ctx.gateway, @gw_hw ) unless @ctx.options.half_duplex
132
127
  end
133
128
 
134
129
  prev_size = @ctx.targets.size
@@ -157,7 +152,7 @@ class ArpSpoofer < ISpoofer
157
152
  @ctx.targets.each do |target|
158
153
  if !target.mac.nil?
159
154
  send_spoofed_packet( @ctx.gateway, @gw_hw, target.ip, target.mac )
160
- send_spoofed_packet( target.ip, target.mac, @ctx.gateway, @gw_hw ) unless @ctx.options[:half_duplex]
155
+ send_spoofed_packet( target.ip, target.mac, @ctx.gateway, @gw_hw ) unless @ctx.options.half_duplex
161
156
  end
162
157
  end
163
158
  sleep 1
@@ -10,17 +10,24 @@ This project is released under the GPL 3 license.
10
10
 
11
11
  =end
12
12
  require 'bettercap/logger'
13
+ require 'socket'
13
14
 
14
15
  class Target
15
16
  attr_accessor :ip, :mac, :vendor, :hostname
16
17
 
18
+ NBNS_TIMEOUT = 30
19
+ NBNS_PORT = 137
20
+ NBNS_BUFSIZE = 65536
21
+ NBNS_REQUEST = "\x82\x28\x0\x0\x0\x1\x0\x0\x0\x0\x0\x0\x20\x43\x4B\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x0\x0\x21\x0\x1"
22
+
17
23
  @@prefixes = nil
18
24
 
19
25
  def initialize( ip, mac=nil )
20
- @ip = ip
21
- @mac = mac
22
- @vendor = Target.lookup_vendor(mac) if not mac.nil?
23
- @hostname = nil # for future use
26
+ @ip = ip
27
+ @mac = mac
28
+ @vendor = Target.lookup_vendor(mac) if not mac.nil?
29
+ @hostname = nil
30
+ @resolver = Thread.new { resolve! }
24
31
  end
25
32
 
26
33
  def mac=(value)
@@ -29,11 +36,46 @@ class Target
29
36
  end
30
37
 
31
38
  def to_s
32
- "#{@ip} : #{@mac}" + ( @vendor ? " ( #{@vendor} )" : "" )
39
+ s = @ip
40
+ s += " ( #{@hostname} )" unless @hostname.nil?
41
+ s += " : #{@mac}"
42
+ s += " ( #{@vendor} )" unless @vendor.nil?
43
+ s
44
+ end
45
+
46
+ def to_s_compact
47
+ if @hostname
48
+ "#{@hostname}/#{@ip}"
49
+ else
50
+ @ip
51
+ end
33
52
  end
34
53
 
35
54
  private
36
55
 
56
+ def resolve!
57
+ resp, sock = nil, nil
58
+ begin
59
+ sock = UDPSocket.open
60
+ sock.send( NBNS_REQUEST, 0, @ip, NBNS_PORT )
61
+ resp = if select([sock], nil, nil, NBNS_TIMEOUT)
62
+ sock.recvfrom(NBNS_BUFSIZE)
63
+ end
64
+ if resp
65
+ @hostname = parse_nbns_response resp
66
+ Logger.info "Found NetBIOS name '#{@hostname}' for address #{@ip}"
67
+ end
68
+ rescue Exception => e
69
+ Logger.debug e
70
+ ensure
71
+ sock.close if sock
72
+ end
73
+ end
74
+
75
+ def parse_nbns_response resp
76
+ resp[0][57,15].to_s.strip
77
+ end
78
+
37
79
  def self.lookup_vendor( mac )
38
80
  if @@prefixes == nil
39
81
  Logger.debug 'Preloading hardware vendor prefixes ...'
@@ -10,6 +10,6 @@ This project is released under the GPL 3 license.
10
10
 
11
11
  =end
12
12
  module BetterCap
13
- VERSION = '1.1.7'
13
+ VERSION = '1.1.8'
14
14
  BANNER = File.read( File.dirname(__FILE__) + '/banner' ).gsub( '#VERSION#', "v#{VERSION}")
15
15
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bettercap
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.7
4
+ version: 1.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simone Margaritelli
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-01 00:00:00.000000000 Z
11
+ date: 2015-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.12.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: network_interface
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.1
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 0.0.1
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: minitest
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -104,6 +118,7 @@ files:
104
118
  - lib/bettercap/logger.rb
105
119
  - lib/bettercap/monkey/packetfu/utils.rb
106
120
  - lib/bettercap/network.rb
121
+ - lib/bettercap/options.rb
107
122
  - lib/bettercap/proxy/certstore.rb
108
123
  - lib/bettercap/proxy/module.rb
109
124
  - lib/bettercap/proxy/proxy.rb