bettercap 1.1.1 → 1.1.2

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.
@@ -20,10 +20,10 @@ class Server
20
20
  @port = port
21
21
  @path = path
22
22
  @server = WEBrick::HTTPServer.new(
23
- :Port => @port,
24
- :DocumentRoot => @path,
25
- :Logger => WEBrick::Log.new("/dev/null"),
26
- :AccessLog => []
23
+ :Port => @port,
24
+ :DocumentRoot => @path,
25
+ :Logger => WEBrick::Log.new("/dev/null"),
26
+ :AccessLog => []
27
27
  )
28
28
  end
29
29
 
@@ -22,53 +22,60 @@ require 'bettercap/discovery/syn'
22
22
  require 'bettercap/discovery/arp'
23
23
 
24
24
  class Network
25
-
26
- def Network.is_ip?(ip)
27
- if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ ip
28
- return $~.captures.all? {|i| i.to_i < 256}
25
+ class << self
26
+ def is_ip?(ip)
27
+ if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ ip
28
+ return $~.captures.all? {|i| i.to_i < 256}
29
+ end
30
+ false
29
31
  end
30
- false
31
- end
32
32
 
33
- def Network.get_gateway
34
- nstat = Shell.execute('netstat -nr')
33
+ def get_gateway
34
+ nstat = Shell.execute('netstat -nr')
35
35
 
36
- Logger.debug "NETSTAT:\n#{nstat}"
37
-
38
- out = nstat.split(/\n/).select {|n| n =~ /UG/ }
39
- gw = out.first.split[1]
40
-
41
- raise BetterCap::Error, 'Could not detect gateway address' unless is_ip?(gw)
42
- gw
43
- end
36
+ Logger.debug "NETSTAT:\n#{nstat}"
44
37
 
45
- def Network.get_local_ips
46
- ips = []
47
-
48
- Shell.ifconfig.split("\n").each do |line|
49
- if line =~ /inet [adr:]*([\d\.]+)/
50
- ips << $1
38
+ out = nstat.split(/\n/).select {|n| n =~ /UG/ }
39
+ gw = nil
40
+ out.each do |line|
41
+ if line.include?( Context.get.options[:iface] )
42
+ gw = line.split[1]
43
+ end
51
44
  end
45
+
46
+ raise BetterCap::Error, 'Could not detect gateway address' unless gw.nil? or is_ip?(gw)
47
+ gw
52
48
  end
53
49
 
54
- ips
55
- end
50
+ def get_local_ips
51
+ ips = []
52
+
53
+ Shell.ifconfig.split("\n").each do |line|
54
+ if line =~ /inet [adr:]*([\d\.]+)/
55
+ ips << $1
56
+ end
57
+ end
56
58
 
57
- def Network.get_alive_targets( ctx, timeout = 5 )
58
- if ctx.options[:arpcache] == false
59
- icmp = IcmpAgent.new timeout
60
- udp = UdpAgent.new ctx.ifconfig, ctx.gateway, ctx.iface[:ip_saddr]
61
- syn = SynAgent.new ctx.ifconfig, ctx.gateway, ctx.iface[:ip_saddr]
62
-
63
- syn.wait
64
- icmp.wait
65
- udp.wait
66
- else
67
- Logger.debug 'Using current ARP cache.'
59
+ ips
68
60
  end
69
61
 
70
- ArpAgent.parse ctx
71
- end
62
+ def get_alive_targets( ctx, timeout = 5 )
63
+ if ctx.options[:arpcache] == false
64
+ icmp = IcmpAgent.new timeout
65
+ udp = UdpAgent.new ctx.ifconfig, ctx.gateway, ctx.ifconfig[:ip_saddr]
66
+ syn = SynAgent.new ctx.ifconfig, ctx.gateway, ctx.ifconfig[:ip_saddr]
67
+ arp = ArpAgent.new ctx.ifconfig, ctx.gateway, ctx.ifconfig[:ip_saddr]
68
+
69
+ syn.wait
70
+ icmp.wait
71
+ arp.wait
72
+ udp.wait
73
+ else
74
+ Logger.debug 'Using current ARP cache.'
75
+ end
76
+
77
+ ArpAgent.parse ctx
78
+ end
72
79
 
73
80
  =begin
74
81
  FIXME:
@@ -83,49 +90,55 @@ class Network
83
90
 
84
91
  won't catch anything, instead we're using cap.stream.each.
85
92
  =end
86
- def Network.get_hw_address( iface, ip_address, attempts = 2 )
87
- hw_address = nil
88
-
89
- attempts.times do
90
- arp_pkt = PacketFu::ARPPacket.new
91
-
92
- arp_pkt.eth_saddr = arp_pkt.arp_saddr_mac = iface[:eth_saddr]
93
- arp_pkt.eth_daddr = 'ff:ff:ff:ff:ff:ff'
94
- arp_pkt.arp_daddr_mac = '00:00:00:00:00:00'
95
- arp_pkt.arp_saddr_ip = iface[:ip_saddr]
96
- arp_pkt.arp_daddr_ip = ip_address
97
-
98
- cap_thread = Thread.new do
99
- target_mac = nil
100
- cap = PacketFu::Capture.new(
101
- :iface => iface[:iface],
102
- :start => true,
103
- :filter => "arp src #{ip_address} and ether dst #{arp_pkt.eth_saddr}"
104
- )
105
- arp_pkt.to_w(iface[:iface])
106
-
107
- timeout = 0
108
-
109
- while target_mac.nil? && timeout <= 5
110
- cap.stream.each do |p|
111
- arp_response = PacketFu::Packet.parse(p)
112
- target_mac = arp_response.arp_saddr_mac if arp_response.arp_saddr_ip == ip_address
113
-
114
- break unless target_mac.nil?
93
+ def get_hw_address( iface, ip_address, attempts = 2 )
94
+ hw_address = nil
95
+
96
+ attempts.times do
97
+ arp_pkt = PacketFu::ARPPacket.new
98
+
99
+ arp_pkt.eth_saddr = arp_pkt.arp_saddr_mac = iface[:eth_saddr]
100
+ arp_pkt.eth_daddr = 'ff:ff:ff:ff:ff:ff'
101
+ arp_pkt.arp_daddr_mac = '00:00:00:00:00:00'
102
+ arp_pkt.arp_saddr_ip = iface[:ip_saddr]
103
+ arp_pkt.arp_daddr_ip = ip_address
104
+
105
+ cap_thread = Thread.new do
106
+ target_mac = nil
107
+ timeout = 0
108
+
109
+ cap = PacketFu::Capture.new(
110
+ :iface => iface[:iface],
111
+ :start => true,
112
+ :filter => "arp src #{ip_address} and ether dst #{arp_pkt.eth_saddr}"
113
+ )
114
+ arp_pkt.to_w(iface[:iface])
115
+
116
+ begin
117
+ Logger.debug 'Attempting to get MAC from packet capture ...'
118
+ target_mac = Timeout::timeout(0.5) { get_mac_from_capture(cap, ip_address) }
119
+ rescue Timeout::Error
120
+ timeout += 0.1
121
+ retry if target_mac.nil? && timeout <= 5
115
122
  end
116
123
 
117
- timeout += 0.1
118
-
119
- Logger.debug 'Retrying ...'
120
- sleep 0.1
124
+ target_mac
121
125
  end
122
- target_mac
126
+ hw_address = cap_thread.value
127
+
128
+ break unless hw_address.nil?
123
129
  end
124
- hw_address = cap_thread.value
125
130
 
126
- break unless hw_address.nil?
131
+ hw_address
127
132
  end
128
133
 
129
- hw_address
134
+ private
135
+
136
+ def get_mac_from_capture( cap, ip_address )
137
+ cap.stream.each do |p|
138
+ arp_response = PacketFu::Packet.parse(p)
139
+ target_mac = arp_response.arp_saddr_mac if arp_response.arp_saddr_ip == ip_address
140
+ break target_mac unless target_mac.nil?
141
+ end
142
+ end
130
143
  end
131
144
  end
@@ -21,7 +21,7 @@ class Module
21
21
  end
22
22
 
23
23
  # we're enabled by default, yo!
24
- def is_enabled?
24
+ def enabled?
25
25
  true
26
26
  end
27
27
 
@@ -52,7 +52,7 @@ class Proxy
52
52
  Logger.info 'Stopping proxy ...'
53
53
 
54
54
  if @socket and @running
55
- @running = false
55
+ @running = false
56
56
  @socket.close
57
57
  end
58
58
  rescue
@@ -115,7 +115,7 @@ class Proxy
115
115
  read += buff.size
116
116
 
117
117
  # collect into the proper object
118
- if not opts[:request].nil? and opts[:request].is_post?
118
+ if not opts[:request].nil? and opts[:request].post?
119
119
  opts[:request] << buff
120
120
  end
121
121
 
@@ -229,7 +229,7 @@ class Proxy
229
229
  break unless not response.headers_done
230
230
  end
231
231
 
232
- if response.is_textual?
232
+ if response.textual?
233
233
  log_stream client_ip, request, response
234
234
 
235
235
  Logger.debug 'Detected textual response'
@@ -40,7 +40,7 @@ class Request
40
40
 
41
41
  line = "#{@verb} #{url} HTTP/1.0"
42
42
 
43
- # get the host header value
43
+ # get the host header value
44
44
  elsif line =~ /^Host: (.*)$/
45
45
  @host = $1
46
46
  if host =~ /([^:]*):([0-9]*)$/
@@ -48,7 +48,7 @@ class Request
48
48
  @port = $2.to_i
49
49
  end
50
50
 
51
- # parse content length, this will speed up data streaming
51
+ # parse content length, this will speed up data streaming
52
52
  elsif line =~ /^Content-Length:\s+(\d+)\s*$/i
53
53
  @content_length = $1.to_i
54
54
 
@@ -65,12 +65,12 @@ class Request
65
65
  @lines << line
66
66
  end
67
67
 
68
- def is_post?
69
- return @verb == 'POST'
68
+ def post?
69
+ @verb == 'POST'
70
70
  end
71
71
 
72
72
  def to_s
73
- return @lines.join("\n") + "\n"
73
+ @lines.join("\n") + "\n"
74
74
  end
75
75
  end
76
76
 
@@ -52,12 +52,12 @@ class Response
52
52
  end
53
53
  end
54
54
 
55
- def is_textual?
55
+ def textual? # textual?
56
56
  @content_type and ( @content_type =~ /^text\/.+/ or @content_type =~ /^application\/.+/ )
57
57
  end
58
58
 
59
59
  def to_s
60
- if is_textual?
60
+ if textual?
61
61
  @headers.map! do |header|
62
62
  # update content length in case the body was
63
63
  # modified
@@ -13,19 +13,19 @@ require 'bettercap/logger'
13
13
  require 'colorize'
14
14
 
15
15
  class BaseParser
16
- def initialize
17
- @filters = []
18
- @name = 'BASE'
19
- end
16
+ def initialize
17
+ @filters = []
18
+ @name = 'BASE'
19
+ end
20
20
 
21
- def on_packet( pkt )
22
- s = pkt.to_s
23
- @filters.each do |filter|
24
- if s =~ filter
25
- Logger.write "[#{pkt.ip_saddr}:#{pkt.tcp_src} > #{pkt.ip_daddr}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
26
- "[#{@name}] ".green +
27
- pkt.payload.strip.yellow
28
- end
29
- end
21
+ def on_packet( pkt )
22
+ s = pkt.to_s
23
+ @filters.each do |filter|
24
+ if s =~ filter
25
+ Logger.write "[#{pkt.ip_saddr}:#{pkt.tcp_src} > #{pkt.ip_daddr}:#{pkt.tcp_dst} #{pkt.proto.last}] " +
26
+ "[#{@name}] ".green +
27
+ pkt.payload.strip.yellow
28
+ end
30
29
  end
30
+ end
31
31
  end
@@ -22,13 +22,30 @@ class Sniffer
22
22
  def self.start( ctx )
23
23
  Logger.info 'Starting sniffer ...'
24
24
 
25
+ pcap = nil
26
+
27
+ if !ctx.options[:sniffer_pcap].nil?
28
+ pcap = PcapFile.new
29
+ Logger.warn "Saving packets to #{ctx.options[:sniffer_pcap]} ."
30
+ end
31
+
25
32
  @@parsers = ParserFactory.load_by_names ctx.options[:parsers]
26
33
 
27
- cap = Capture.new(:iface => ctx.options[:iface], :start => true)
34
+ cap = Capture.new(
35
+ :iface => ctx.options[:iface],
36
+ :filter => ctx.options[:sniffer_filter],
37
+ :start => true
38
+ )
28
39
  cap.stream.each do |p|
40
+ begin
41
+ pcap.array_to_file( :filename => ctx.options[:sniffer_pcap], :array => [p], :append => true) unless pcap.nil?
42
+ rescue Exception => e
43
+ Logger.warn e.message
44
+ end
45
+
29
46
  pkt = Packet.parse p
30
47
  if not pkt.nil? and pkt.is_ip?
31
- next if ( pkt.ip_saddr == ctx.iface[:ip_saddr] or pkt.ip_daddr == ctx.iface[:ip_saddr] ) and !ctx.options[:local]
48
+ next if ( pkt.ip_saddr == ctx.ifconfig[:ip_saddr] or pkt.ip_daddr == ctx.ifconfig[:ip_saddr] ) and !ctx.options[:local]
32
49
 
33
50
  @@parsers.each do |parser|
34
51
  begin
@@ -27,7 +27,7 @@ class ArpSpoofer < ISpoofer
27
27
  Logger.debug 'ARP SPOOFER SELECTED'
28
28
 
29
29
  Logger.info "Getting gateway #{@ctx.gateway} MAC address ..."
30
- @gw_hw = Network.get_hw_address( @ctx.iface, @ctx.gateway )
30
+ @gw_hw = Network.get_hw_address( @ctx.ifconfig, @ctx.gateway )
31
31
  if @gw_hw.nil?
32
32
  raise BetterCap::Error, "Couldn't determine router MAC"
33
33
  end
@@ -45,7 +45,7 @@ class ArpSpoofer < ISpoofer
45
45
  pkt.arp_daddr_ip = daddr
46
46
  pkt.arp_opcode = 2
47
47
 
48
- pkt.to_w(@ctx.iface[:iface])
48
+ pkt.to_w(@ctx.ifconfig[:iface])
49
49
  end
50
50
 
51
51
  def start
@@ -84,7 +84,7 @@ class ArpSpoofer < ISpoofer
84
84
  if target.mac.nil?
85
85
  Logger.warn "Getting target #{target.ip} MAC address ..."
86
86
 
87
- hw = Network.get_hw_address( @ctx.iface, target.ip, 1 )
87
+ hw = Network.get_hw_address( @ctx.ifconfig, target.ip, 1 )
88
88
  if hw.nil?
89
89
  Logger.warn "Couldn't determine target MAC"
90
90
  next
@@ -95,8 +95,8 @@ class ArpSpoofer < ISpoofer
95
95
  end
96
96
  end
97
97
 
98
- send_spoofed_packed @ctx.gateway, @ctx.iface[:eth_saddr], target.ip, target.mac
99
- send_spoofed_packed target.ip, @ctx.iface[:eth_saddr], @ctx.gateway, @gw_hw
98
+ send_spoofed_packed @ctx.gateway, @ctx.ifconfig[:eth_saddr], target.ip, target.mac
99
+ send_spoofed_packed target.ip, @ctx.ifconfig[:eth_saddr], @ctx.gateway, @gw_hw
100
100
  end
101
101
 
102
102
  prev_size = @ctx.targets.size
@@ -17,36 +17,36 @@ class Target
17
17
  @@prefixes = nil
18
18
 
19
19
  def initialize( ip, mac )
20
- @ip = ip
21
- @mac = mac
22
- @vendor = Target.lookup_vendor(mac) if not mac.nil?
23
- @hostname = nil # for future use
20
+ @ip = ip
21
+ @mac = mac
22
+ @vendor = Target.lookup_vendor(mac) if not mac.nil?
23
+ @hostname = nil # for future use
24
24
  end
25
25
 
26
26
  def mac=(value)
27
- @mac = value
28
- @vendor = Target.lookup_vendor(@mac) if not @mac.nil?
27
+ @mac = value
28
+ @vendor = Target.lookup_vendor(@mac) if not @mac.nil?
29
29
  end
30
30
 
31
31
  def to_s
32
- "#{@ip} : #{@mac}" + ( @vendor ? " ( #{@vendor} )" : "" )
32
+ "#{@ip} : #{@mac}" + ( @vendor ? " ( #{@vendor} )" : "" )
33
33
  end
34
34
 
35
35
  private
36
36
 
37
37
  def self.lookup_vendor( mac )
38
- if @@prefixes == nil
39
- Logger.debug 'Preloading hardware vendor prefixes ...'
40
-
41
- @@prefixes = {}
42
- filename = File.dirname(__FILE__) + '/hw-prefixes'
43
- File.open( filename ).each do |line|
44
- if line =~ /^([A-F0-9]{6})\s(.+)$/
45
- @@prefixes[$1] = $2
46
- end
47
- end
38
+ if @@prefixes == nil
39
+ Logger.debug 'Preloading hardware vendor prefixes ...'
40
+
41
+ @@prefixes = {}
42
+ filename = File.dirname(__FILE__) + '/hw-prefixes'
43
+ File.open( filename ).each do |line|
44
+ if line =~ /^([A-F0-9]{6})\s(.+)$/
45
+ @@prefixes[$1] = $2
46
+ end
48
47
  end
48
+ end
49
49
 
50
- @@prefixes[ mac.split(':')[0,3].join('').upcase ]
50
+ @@prefixes[ mac.split(':')[0,3].join('').upcase ]
51
51
  end
52
52
  end