bettercap 1.3.6 → 1.3.7

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.
@@ -48,6 +48,23 @@ class Response
48
48
  r
49
49
  end
50
50
 
51
+ # Return a 302 response object redirecting to +url+, setting optional +cookies+.
52
+ def self.redirect( url, cookies = [] )
53
+ r = Response.new
54
+
55
+ r << "HTTP/1.1 302 Moved"
56
+ r << "Location: #{url}"
57
+
58
+ cookies.each do |cookie|
59
+ r << "Set-Cookie: #{cookie}"
60
+ end
61
+
62
+ r << "Connection: close"
63
+ r << "\n\n"
64
+
65
+ r
66
+ end
67
+
51
68
  # Initialize this response object state.
52
69
  def initialize
53
70
  @content_type = nil
@@ -158,7 +175,7 @@ class Response
158
175
  end
159
176
  end
160
177
 
161
- @headers.join("\n") + "\n" + @body
178
+ @headers.join("\n") + "\n" + ( @body || "\n" )
162
179
  end
163
180
  end
164
181
 
@@ -78,8 +78,7 @@ class Strip
78
78
  unless @cookies.is_clean?(request)
79
79
  Logger.info "[#{'SSLSTRIP'.green} #{request.client}] Sending expired cookies for '#{request.host}'."
80
80
  expired = @cookies.get_expired_headers!(request)
81
-
82
- response = build_expired_cookies( expired, request )
81
+ response = Response.redirect( "http://#{request.host}#{request.url}", expired )
83
82
  end
84
83
  response
85
84
  end
@@ -156,22 +155,6 @@ class Strip
156
155
  end
157
156
  end
158
157
  end
159
-
160
- # Return a 302 Redirect BetterCap::Proxy::Response object for the
161
- # +request+, using +expired+ cookie headers to kill a client session.
162
- def build_expired_cookies( expired, request )
163
- resp = Response.new
164
-
165
- resp << "HTTP/1.1 302 Moved"
166
- resp << "Connection: close"
167
- resp << "Location: http://#{request.host}#{request.url}"
168
-
169
- expired.each do |cookie|
170
- resp << "Set-Cookie: #{cookie}"
171
- end
172
-
173
- resp
174
- end
175
158
  end
176
159
 
177
160
  end
@@ -24,6 +24,8 @@ class StreamLogger
24
24
  '5' => :red
25
25
  }
26
26
 
27
+ @@services = nil
28
+
27
29
  # Search for the +addr+ IP address inside the list of collected targets and return
28
30
  # its compact string representation ( @see BetterCap::Target#to_s_compact ).
29
31
  def self.addr2s( addr, alt = nil )
@@ -36,17 +38,48 @@ class StreamLogger
36
38
 
37
39
  if addr == '0.0.0.0' and !alt.nil?
38
40
  return alt
41
+ elsif addr == '255.255.255.255'
42
+ return '*'
39
43
  end
40
44
 
41
45
  addr
42
46
  end
43
47
 
48
+ # Given +proto+ and +port+ return the network service name if possible.
49
+ def self.service( proto, port )
50
+ if @@services.nil?
51
+ Logger.info 'Preloading network services ...'
52
+
53
+ @@services = { :tcp => {}, :udp => {} }
54
+ filename = File.dirname(__FILE__) + '/../network/services'
55
+ File.open( filename ).each do |line|
56
+ if line =~ /([^\s]+)\s+(\d+)\/([a-z]+).*/i
57
+ @@services[$3.to_sym][$2.to_i] = $1
58
+ end
59
+ end
60
+ end
61
+
62
+ if @@services.has_key?(proto) and @@services[proto].has_key?(port)
63
+ @@services[proto][port]
64
+ else
65
+ port
66
+ end
67
+ end
68
+
44
69
  # Log a raw packet ( +pkt+ ) data +payload+ using the specified +label+.
45
70
  def self.log_raw( pkt, label, payload )
46
- nl = if label.include?"\n" then "\n" else " " end
71
+ nl = label.include?("\n") ? "\n" : " "
47
72
  label = label.strip
48
- Logger.raw( "[#{self.addr2s(pkt.ip_saddr, pkt.eth2s(:src))} > #{self.addr2s(pkt.ip_daddr,pkt.eth2s(:dst))}#{pkt.respond_to?('tcp_dst') ? ':' + pkt.tcp_dst.to_s : ''}] " \
49
- "[#{label.green}]#{nl}#{payload.strip}" )
73
+ from = self.addr2s( pkt.ip_saddr, pkt.eth2s(:src) )
74
+ to = self.addr2s( pkt.ip_daddr, pkt.eth2s(:dst) )
75
+
76
+ if pkt.respond_to?('tcp_dst')
77
+ to += ':' + self.service( :tcp, pkt.tcp_dst ).to_s
78
+ elsif pkt.respond_to?('udp_dst')
79
+ to += ':' + self.service( :udp, pkt.udp_dst ).to_s
80
+ end
81
+
82
+ Logger.raw( "[#{from} > #{to}] [#{label.green}]#{nl}#{payload.strip}" )
50
83
  end
51
84
 
52
85
  # Log a HTTP ( HTTPS if +is_https+ is true ) stream performed by the +client+
@@ -29,8 +29,7 @@ class Streamer
29
29
 
30
30
  Logger.warn "#{client_ip}:#{client_port} is connecting to us directly."
31
31
 
32
- client.write "HTTP/1.1 302 Found\n"
33
- client.write "Location: https://www.youtube.com/watch?v=dQw4w9WgXcQ\n\n"
32
+ client.write Response.redirect( "https://www.youtube.com/watch?v=dQw4w9WgXcQ" ).to_s
34
33
  end
35
34
 
36
35
  # Handle the HTTP +request+ from +client+.
@@ -21,7 +21,7 @@ class DHCP < Base
21
21
  unless packet.nil?
22
22
  auth = packet.authentication
23
23
  cid = auth.nil?? nil : packet.client_identifier
24
- msg = "[#{packet.type.yellow}] #{'Transaction-ID'.green}=#{packet.transaction_id.yellow}"
24
+ msg = "[#{packet.type.yellow}] #{'Transaction-ID'.green}=#{sprintf( "0x%X", packet.xid ).yellow}"
25
25
 
26
26
  unless cid.nil?
27
27
  msg += " #{'Client-ID'.green}='#{cid.yellow}'"
@@ -38,10 +38,7 @@ class DHCP < Base
38
38
  StreamLogger.log_raw( pkt, 'DHCP', msg )
39
39
  end
40
40
  end
41
- rescue Exception => e
42
- Logger.debug e.message
43
- Logger.debug e.backtrace.join("\n")
44
- end
41
+ rescue; end
45
42
  end
46
43
  end
47
44
  end
@@ -35,8 +35,8 @@ class Httpauth < Base
35
35
 
36
36
  StreamLogger.log_raw( pkt, 'HTTP BASIC AUTH', "http://#{hostname}#{path} - username=#{user} password=#{pass}".yellow )
37
37
 
38
- elsif line =~ /Authorization:\s*Digest\s+(.+)/i
39
- StreamLogger.log_raw( pkt, 'HTTP DIGEST AUTH', "http://#{hostname}#{path}\n#{$1}".yellow )
38
+ elsif line =~ /Authorization:\s*([^\s]+)\s+(.+)/i
39
+ StreamLogger.log_raw( pkt, "HTTP #{$1} AUTH", "http://#{hostname}#{path}\n#{$1.blue}: #{$2.yellow}" )
40
40
  end
41
41
  end
42
42
  end
@@ -0,0 +1,27 @@
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
+ module Parsers
16
+ # MySQL authentication parser.
17
+ class MySQL < Base
18
+ def on_packet( pkt )
19
+ packet = Network::Protos::MySQL::Packet.parse( pkt.payload )
20
+ unless packet.nil? or !packet.is_auth?
21
+ StreamLogger.log_raw( pkt, 'MYSQL', "#{'username'.blue}='#{packet.username.yellow}' "\
22
+ "#{'password'.blue}='#{packet.password.map { |x| sprintf("%02X", x )}.join.yellow}'" )
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -13,26 +13,20 @@ This project is released under the GPL 3 license.
13
13
 
14
14
  module BetterCap
15
15
  module Parsers
16
- # NTLMSS traffic parser.
17
- class Ntlmss < Base
18
- # Convert binary +data+ into human readable hexadecimal representation.
19
- def bin2hex( data )
20
- hex = ''
21
- data.each_byte do |byte|
22
- if /[[:print:]]/ === byte.chr
23
- hex += byte.chr
24
- else
25
- hex += "\\x" + byte.to_s(16)
26
- end
27
- end
28
- hex
29
- end
30
-
16
+ # NTLMSS authentication parser.
17
+ class NTLMSS < Base
31
18
  def on_packet( pkt )
32
- s = pkt.to_s
33
- if s =~ /NTLMSSP\x00\x03\x00\x00\x00.+/
34
- # TODO: Parse NTLMSSP packet.
35
- StreamLogger.log_raw( pkt, 'NTLMSS', bin2hex( pkt.payload ) )
19
+ packet = Network::Protos::NTLM::Packet.parse( pkt.payload )
20
+ if !packet.nil? and packet.is_auth?
21
+ msg = "NTLMSSP Authentication:\n"
22
+ msg += " #{'LM Response'.blue} : #{packet.lm_response.map { |x| sprintf("%02X", x )}.join.yellow}\n"
23
+ msg += " #{'NTLM Response'.blue} : #{packet.ntlm_response.map { |x| sprintf("%02X", x )}.join.yellow}\n"
24
+ msg += " #{'Domain Name'.blue} : #{packet.domain_name.yellow}\n"
25
+ msg += " #{'User Name'.blue} : #{packet.user_name.yellow}\n"
26
+ msg += " #{'Host Name'.blue} : #{packet.host_name.yellow}\n"
27
+ msg += " #{'Session Key'.blue} : #{packet.session_key_resp.map { |x| sprintf("%02X", x )}.join.yellow}"
28
+
29
+ StreamLogger.log_raw( pkt, 'NTLM', msg )
36
30
  end
37
31
  end
38
32
  end
@@ -0,0 +1,36 @@
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
+ module Parsers
16
+ # PgSQL authentication parser.
17
+ class PgSQL < Base
18
+ STARTUP_EXPR = /....\x00\x03\x00\x00user\x00([^\x00]+)\x00database\x00([^\x00]+)/
19
+ MD5_AUTH_REQ_EXPR = /\x52....\x00\x00\x00\x05(....)/
20
+ MD5_PASSWORD_EXPR = /\x70....md5(.+)/
21
+
22
+ def on_packet( pkt )
23
+ if pkt.payload =~ STARTUP_EXPR
24
+ StreamLogger.log_raw( pkt, 'PGSQL', "STARTUP #{'username'.blue}='#{$1.yellow}' #{'database'.blue}='#{$2.yellow}'" )
25
+
26
+ elsif pkt.payload =~ MD5_AUTH_REQ_EXPR
27
+ salt = $1.reverse.unpack('L')[0]
28
+ StreamLogger.log_raw( pkt, 'PGSQL', "MD5 AUTH REQUEST #{'salt'.blue}=#{sprintf("0x%X", salt).yellow}" )
29
+
30
+ elsif pkt.payload =~ MD5_PASSWORD_EXPR
31
+ StreamLogger.log_raw( pkt, 'PGSQL', "PASSWORD #{'md5'.blue}='#{$1.yellow}'" )
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -34,18 +34,25 @@ class Sniffer
34
34
 
35
35
  setup( ctx )
36
36
 
37
- self.stream.each do |p|
37
+ self.stream.each do |raw_packet|
38
38
  break unless @@ctx.running
39
39
  begin
40
- parsed = Packet.parse p
40
+ parsed = PacketFu::Packet.parse(raw_packet)
41
41
  rescue Exception => e
42
42
  parsed = nil
43
- Logger.debug e.message
43
+ #Logger.debug e.message
44
+ #Logger.debug e.backtrace.join("\n")
44
45
  end
45
46
 
46
47
  if not parsed.nil? and parsed.is_ip? and !skip_packet?(parsed)
47
- append_packet p
48
+ Logger.debug "Parsing packet ..."
49
+ append_packet raw_packet
48
50
  parse_packet parsed
51
+ else
52
+ Logger.debug "[SNIFFER] Skipping packet:" \
53
+ " parsed=#{parsed.nil?? 'false' : 'true'}" \
54
+ " is_ip?=#{parsed.nil?? 'false' : parsed.is_ip?}" \
55
+ " skip_packet?=#{parsed.nil?? 'true' : skip_packet?(parsed)}"
49
56
  end
50
57
  end
51
58
  end
@@ -66,9 +73,12 @@ class Sniffer
66
73
 
67
74
  # Return true if the +pkt+ packet instance must be skipped.
68
75
  def self.skip_packet?( pkt )
69
- !@@ctx.options.local and
70
- ( pkt.ip_saddr == @@ctx.ifconfig[:ip_saddr] or
71
- pkt.ip_daddr == @@ctx.ifconfig[:ip_saddr] )
76
+ begin
77
+ !@@ctx.options.local and
78
+ ( pkt.ip_saddr == @@ctx.ifconfig[:ip_saddr] or
79
+ pkt.ip_daddr == @@ctx.ifconfig[:ip_saddr] )
80
+ rescue; end
81
+ false
72
82
  end
73
83
 
74
84
  # Apply each parser on the given +parsed+ packet.
@@ -77,7 +87,7 @@ class Sniffer
77
87
  begin
78
88
  parser.on_packet parsed
79
89
  rescue Exception => e
80
- Logger.warn e.message
90
+ Logger.debug e.message
81
91
  end
82
92
  end
83
93
  end
@@ -12,7 +12,7 @@ This project is released under the GPL 3 license.
12
12
  =end
13
13
  module BetterCap
14
14
  # Current version of bettercap.
15
- VERSION = '1.3.6'
15
+ VERSION = '1.3.7'
16
16
  # Program banner.
17
17
  BANNER = File.read( File.dirname(__FILE__) + '/banner' ).gsub( '#VERSION#', "v#{VERSION}")
18
18
  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.3.6
4
+ version: 1.3.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simone Margaritelli
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-06 00:00:00.000000000 Z
11
+ date: 2016-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -141,8 +141,11 @@ files:
141
141
  - lib/bettercap/network/packet_queue.rb
142
142
  - lib/bettercap/network/protos/base.rb
143
143
  - lib/bettercap/network/protos/dhcp.rb
144
+ - lib/bettercap/network/protos/mysql.rb
145
+ - lib/bettercap/network/protos/ntlm.rb
144
146
  - lib/bettercap/network/servers/dnsd.rb
145
147
  - lib/bettercap/network/servers/httpd.rb
148
+ - lib/bettercap/network/services
146
149
  - lib/bettercap/network/target.rb
147
150
  - lib/bettercap/options.rb
148
151
  - lib/bettercap/proxy/certstore.rb
@@ -172,8 +175,10 @@ files:
172
175
  - lib/bettercap/sniffer/parsers/irc.rb
173
176
  - lib/bettercap/sniffer/parsers/mail.rb
174
177
  - lib/bettercap/sniffer/parsers/mpd.rb
178
+ - lib/bettercap/sniffer/parsers/mysql.rb
175
179
  - lib/bettercap/sniffer/parsers/nntp.rb
176
180
  - lib/bettercap/sniffer/parsers/ntlmss.rb
181
+ - lib/bettercap/sniffer/parsers/pgsql.rb
177
182
  - lib/bettercap/sniffer/parsers/post.rb
178
183
  - lib/bettercap/sniffer/parsers/redis.rb
179
184
  - lib/bettercap/sniffer/parsers/rlogin.rb