bettercap 1.1.10 → 1.2.0

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/TODO.md +8 -7
  3. data/bin/bettercap +8 -2
  4. data/lib/bettercap.rb +5 -4
  5. data/lib/bettercap/context.rb +54 -8
  6. data/lib/bettercap/discovery/agents/arp.rb +17 -4
  7. data/lib/bettercap/discovery/agents/base.rb +16 -52
  8. data/lib/bettercap/discovery/agents/icmp.rb +25 -17
  9. data/lib/bettercap/discovery/agents/udp.rb +9 -20
  10. data/lib/bettercap/discovery/{discovery.rb → thread.rb} +10 -9
  11. data/lib/bettercap/error.rb +1 -2
  12. data/lib/bettercap/factories/{firewall_factory.rb → firewall.rb} +11 -7
  13. data/lib/bettercap/factories/{parser_factory.rb → parser.rb} +13 -3
  14. data/lib/bettercap/factories/{spoofer_factory.rb → spoofer.rb} +10 -3
  15. data/lib/bettercap/firewalls/base.rb +76 -0
  16. data/lib/bettercap/firewalls/linux.rb +26 -16
  17. data/lib/bettercap/firewalls/osx.rb +22 -13
  18. data/lib/bettercap/firewalls/redirection.rb +15 -1
  19. data/lib/bettercap/httpd/server.rb +5 -0
  20. data/lib/bettercap/logger.rb +29 -8
  21. data/lib/bettercap/network.rb +105 -105
  22. data/lib/bettercap/options.rb +99 -41
  23. data/lib/bettercap/packet_queue.rb +92 -0
  24. data/lib/bettercap/proxy/certstore.rb +49 -43
  25. data/lib/bettercap/proxy/module.rb +4 -2
  26. data/lib/bettercap/proxy/proxy.rb +7 -2
  27. data/lib/bettercap/proxy/request.rb +28 -16
  28. data/lib/bettercap/proxy/response.rb +23 -2
  29. data/lib/bettercap/proxy/stream_logger.rb +6 -0
  30. data/lib/bettercap/proxy/streamer.rb +13 -5
  31. data/lib/bettercap/proxy/thread_pool.rb +6 -14
  32. data/lib/bettercap/shell.rb +5 -3
  33. data/lib/bettercap/sniffer/parsers/base.rb +7 -1
  34. data/lib/bettercap/sniffer/parsers/custom.rb +6 -1
  35. data/lib/bettercap/sniffer/parsers/ftp.rb +8 -5
  36. data/lib/bettercap/sniffer/parsers/httpauth.rb +4 -1
  37. data/lib/bettercap/sniffer/parsers/https.rb +4 -1
  38. data/lib/bettercap/sniffer/parsers/irc.rb +8 -5
  39. data/lib/bettercap/sniffer/parsers/mail.rb +8 -5
  40. data/lib/bettercap/sniffer/parsers/ntlmss.rb +21 -18
  41. data/lib/bettercap/sniffer/parsers/post.rb +4 -1
  42. data/lib/bettercap/sniffer/parsers/url.rb +4 -1
  43. data/lib/bettercap/sniffer/sniffer.rb +7 -3
  44. data/lib/bettercap/spoofers/arp.rb +69 -94
  45. data/lib/bettercap/spoofers/base.rb +132 -0
  46. data/lib/bettercap/spoofers/icmp.rb +200 -0
  47. data/lib/bettercap/spoofers/none.rb +8 -2
  48. data/lib/bettercap/target.rb +117 -90
  49. data/lib/bettercap/update_checker.rb +6 -0
  50. data/lib/bettercap/version.rb +3 -1
  51. metadata +24 -8
  52. data/lib/bettercap/base/ifirewall.rb +0 -46
  53. data/lib/bettercap/base/ispoofer.rb +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 397d0cf63901e645278f09bb5b2eafd9745945ed
4
- data.tar.gz: 8c67517734bb52946622f279c5590301b592f7d6
3
+ metadata.gz: a830b906b0c9ea8c95b66699910e60e79c1eb728
4
+ data.tar.gz: 607fb72b1fd6dc77b4481ff2c3d8cb2dddefc8d3
5
5
  SHA512:
6
- metadata.gz: 6957c7da7b6781a1efdf229b93ce565d875f32ee6a8ccaa6361767ef2b31b79f421400b21397f5b3717aef7b065afd97a7e37de3a1c3efeaeab44ca6cd224d51
7
- data.tar.gz: fb5dd3cdc11a9b7ce6406e02cac9632204aba0ded518ea46335689bef6ceb690f678e23dcad29b07c4013c65c27034f57a18f82c2bc0681902d79d9b6e7e0d66
6
+ metadata.gz: 37ffe1a82e6da08ea9e1136892a9ec1b720b8fd5841eb74370e6e462151aa004e8ad0a3391d0db449dae5b5b86f2c5f7fe7d752c42566500039b1b7f478e677d
7
+ data.tar.gz: 1a2c0b6e2035a144bf677adaefba785abf614b375d9bb9d0d5284232ec1bac9cff467272eca2c3fa01e8acdbaf0c66ec726f47f6ba60e380bce61be615d2779e
data/TODO.md CHANGED
@@ -9,11 +9,13 @@ This is a list of TODOs I use to keep track of tasks and upcoming features.
9
9
  - [x] Use StreamLogger for both Proxy and Sniffer traffic.
10
10
  - [x] Implement `--custom-parser REGEX` option.
11
11
  - [x] Let `-T|--target` [support MAC addresses](https://github.com/evilsocket/bettercap/issues/82).
12
- - [ ] Implement event-driven core plugin infrastructure ( for webui, etc ).
13
- - [ ] Implement web-ui core plugin.
12
+ - [x] Fix modules structure by folder.
13
+ - [x] Document classes with RDoc.
14
+ - [x] ICMP Redirect ( double direct )
15
+ - [ ] Implement `--mkcert FILENAME` option to create custom HTTPS `crt` files.
16
+ - [ ] Implement sslstrip+ support.
14
17
  - [ ] Rewrite proxy class using [em-proxy](https://github.com/igrigorik/em-proxy) library.
15
18
  - [ ] HTTP/2 Support.
16
- - [ ] IPV6 Support.
17
19
 
18
20
  **Platform Specific**
19
21
 
@@ -23,7 +25,6 @@ This is a list of TODOs I use to keep track of tasks and upcoming features.
23
25
 
24
26
  **Maybe**
25
27
 
26
- - [ ] ICMP Redirect ? ( only half duplex and filtered by many firewalls anyway ... dunno ).
27
- - [ ] DNS Spoofing ( not sure if it actually makes any sense ).
28
- - [ ] sslstrip ( not really sure, currently is quite useless )
29
- - [ ] Implement `--mkcert FILENAME` option to create custom HTTPS `crt` files.
28
+ - [ ] Implement event-driven core plugin infrastructure ( for webui, etc ).
29
+ - [ ] Implement web-ui core plugin.
30
+ - [ ] IPV6 Support.
data/bin/bettercap CHANGED
@@ -56,7 +56,7 @@ begin
56
56
  # Start network sniffer.
57
57
  if ctx.options.sniffer
58
58
  BetterCap::Sniffer.start ctx
59
- else
59
+ elsif ctx.options.has_spoofer?
60
60
  BetterCap::Logger.warn 'WARNING: Sniffer module was NOT enabled ( -X argument ), this '\
61
61
  'will cause the MITM to run but no data to be collected.' unless ctx.options.has_spoofer?
62
62
  end
@@ -68,11 +68,17 @@ begin
68
68
  rescue SystemExit, Interrupt
69
69
  BetterCap::Logger.raw "\n"
70
70
 
71
- rescue BetterCap::Error => e
71
+ rescue OptionParser::InvalidOption => e
72
+ BetterCap::Logger.error e.message
72
73
 
74
+ rescue OptionParser::AmbiguousOption => e
75
+ BetterCap::Logger.error e.message
76
+
77
+ rescue BetterCap::Error => e
73
78
  BetterCap::Logger.error e.message
74
79
 
75
80
  rescue Exception => e
81
+ BetterCap::Logger.error "EXCEPTION '#{e.class}' :"
76
82
  BetterCap::Logger.error e.message
77
83
  BetterCap::Logger.error e.backtrace.join("\n")
78
84
 
data/lib/bettercap.rb CHANGED
@@ -27,16 +27,17 @@ Config = RbConfig
27
27
  require 'bettercap/update_checker'
28
28
  require 'bettercap/error'
29
29
  require 'bettercap/options'
30
+ require 'bettercap/packet_queue'
31
+ require 'bettercap/discovery/thread'
30
32
  require 'bettercap/discovery/agents/base'
31
33
  require 'bettercap/discovery/agents/arp'
32
34
  require 'bettercap/discovery/agents/icmp'
33
35
  require 'bettercap/discovery/agents/udp'
34
- require 'bettercap/discovery/discovery'
35
36
  require 'bettercap/context'
36
37
  require 'bettercap/monkey/packetfu/utils'
37
- require 'bettercap/factories/firewall_factory'
38
- require 'bettercap/factories/spoofer_factory'
39
- require 'bettercap/factories/parser_factory'
38
+ require 'bettercap/factories/firewall'
39
+ require 'bettercap/factories/spoofer'
40
+ require 'bettercap/factories/parser'
40
41
  require 'bettercap/logger'
41
42
  require 'bettercap/shell'
42
43
  require 'bettercap/network'
@@ -10,21 +10,48 @@ This project is released under the GPL 3 license.
10
10
 
11
11
  =end
12
12
 
13
- # this class holds global states & data
14
13
  require 'bettercap/error'
15
14
 
16
15
  module BetterCap
16
+ # This class holds global states and data, moreover it exposes high level
17
+ # methods to manipulate the program behaviour.
17
18
  class Context
18
- attr_accessor :options, :ifconfig, :firewall, :gateway,
19
- :targets, :discovery, :spoofer, :httpd,
20
- :certificate, :running
19
+ # Instance of BetterCap::Options class.
20
+ attr_accessor :options
21
+ # A dictionary containing information about the selected network interface.
22
+ attr_accessor :ifconfig
23
+ # Instance of the current BetterCap::Firewalls class.
24
+ attr_accessor :firewall
25
+ # Network gateway IP address.
26
+ attr_accessor :gateway
27
+ # A list of BetterCap::Target objects which is periodically updated.
28
+ attr_accessor :targets
29
+ # Instance of BetterCap::Discovery::Thread class.
30
+ attr_accessor :discovery
31
+ # A list of BetterCap::Spoofers class instances.
32
+ attr_accessor :spoofer
33
+ # Instance of BetterCap::HTTPD::Server class.
34
+ attr_accessor :httpd
35
+ # Instance of OpenSSL::X509::Certificate class used
36
+ # for the HTTPS transparent proxy.
37
+ attr_accessor :certificate
38
+ # Set to true if the program is running, to false if a shutdown was
39
+ # scheduled by the user which pressed CTRL+C
40
+ attr_accessor :running
41
+ # Timeout for discovery operations.
42
+ attr_reader :timeout
43
+ # Instance of BetterCap::PacketQueue.
44
+ attr_reader :packets
21
45
 
22
46
  @@instance = nil
23
47
 
48
+ # Return the global instance of the program Context, if the instance
49
+ # was not yet created it will be initialized and returned.
24
50
  def self.get
25
51
  @@instance ||= self.new
26
52
  end
27
53
 
54
+ # Initialize the global context object.
28
55
  def initialize
29
56
  begin
30
57
  iface = Pcap.lookupdev
@@ -34,6 +61,7 @@ class Context
34
61
  end
35
62
 
36
63
  @running = true
64
+ @timeout = 5
37
65
  @options = Options.new iface
38
66
  @ifconfig = nil
39
67
  @firewall = nil
@@ -45,10 +73,12 @@ class Context
45
73
  @certificate = nil
46
74
  @proxies = []
47
75
  @redirections = []
48
- @discovery = Discovery.new self
49
- @firewall = FirewallFactory.get_firewall
76
+ @discovery = Discovery::Thread.new self
77
+ @firewall = Factories::Firewall.get
78
+ @packets = nil
50
79
  end
51
80
 
81
+ # Update the Context state parsing network related informations.
52
82
  def update!
53
83
  @ifconfig = PacketFu::Utils.ifconfig @options.iface
54
84
  @gateway = Network.get_gateway if @gateway.nil?
@@ -61,10 +91,20 @@ class Context
61
91
  'correct network configuration, this could also happen if bettercap '\
62
92
  'is launched from a virtual environment.' if @gateway.nil? or !Network.is_ip?(@gateway)
63
93
 
64
- Logger.debug "network=#{@ifconfig[:ip4_obj]} gateway=#{@gateway} local_ip=#{@ifconfig[:ip_saddr]}"
65
- Logger.debug "IFCONFIG: #{@ifconfig.inspect}"
94
+ Logger.debug '----- NETWORK INFORMATIONS -----'
95
+ Logger.debug " network = #{@ifconfig[:ip4_obj]}"
96
+ Logger.debug " gateway = #{@gateway}"
97
+ Logger.debug " local_ip = #{@ifconfig[:ip_saddr]}\n"
98
+ @ifconfig.each do |key,value|
99
+ Logger.debug " ifconfig[:#{key}] = #{value}"
100
+ end
101
+ Logger.debug "--------------------------------\n"
102
+
103
+ @packets = PacketQueue.new( @ifconfig[:iface], 4 )
66
104
  end
67
105
 
106
+ # Find a target given its +ip+ and +mac+ addresses inside the #targets
107
+ # list, if not found return nil.
68
108
  def find_target ip, mac
69
109
  @targets.each do |target|
70
110
  if target.equals?(ip,mac)
@@ -74,6 +114,7 @@ class Context
74
114
  nil
75
115
  end
76
116
 
117
+ # Apply needed BetterCap::Firewalls::Redirection objects.
77
118
  def enable_port_redirection!
78
119
  @redirections = @options.to_redirections @ifconfig
79
120
  @redirections.each do |r|
@@ -82,6 +123,8 @@ class Context
82
123
  end
83
124
  end
84
125
 
126
+ # Initialize the needed transparent proxies and the processor routined which
127
+ # is needed in order to run proxy modules.
85
128
  def create_proxies
86
129
  if @options.has_proxy_module?
87
130
  require @options.proxy_module
@@ -135,12 +178,15 @@ class Context
135
178
  end
136
179
  end
137
180
 
181
+ # Stop every running daemon that was started and reset system state.
138
182
  def finalize
139
183
  @running = false
140
184
 
141
185
  # Logger is silent if @running == false
142
186
  puts "\nShutting down, hang on ...\n"
143
187
 
188
+ @packets.stop
189
+
144
190
  Logger.debug 'Stopping target discovery manager ...'
145
191
  @discovery.stop
146
192
 
@@ -12,7 +12,14 @@ This project is released under the GPL 3 license.
12
12
 
13
13
  # Parse the ARP table searching for new hosts.
14
14
  module BetterCap
15
- class ArpAgent < BaseAgent
15
+ module Discovery
16
+ module Agents
17
+ # Class responsible to parse ARP cache and send ARP probes to each
18
+ # possible IP on the network.
19
+ class Arp < Discovery::Agents::Base
20
+ # Parse the current ARP cache and return a list of BetterCap::Target
21
+ # objects which are found inside it, using the +ctx+ BetterCap::Context
22
+ # instance.
16
23
  def self.parse( ctx )
17
24
  targets = []
18
25
  self.parse_cache do |ip,mac|
@@ -33,6 +40,8 @@ class ArpAgent < BaseAgent
33
40
  targets
34
41
  end
35
42
 
43
+ # Parse the ARP cache searching for the given IP +address+ and return its
44
+ # MAC if found, otherwise nil.
36
45
  def self.find_address( address )
37
46
  self.parse_cache do |ip,mac|
38
47
  if ip == address
@@ -42,6 +51,8 @@ class ArpAgent < BaseAgent
42
51
  nil
43
52
  end
44
53
 
54
+ # Parse the ARP cache searching for the given MAC +address+ and return its
55
+ # IP if found, otherwise nil.
45
56
  def self.find_mac( address )
46
57
  self.parse_cache do |ip,mac|
47
58
  if mac == address
@@ -70,16 +81,18 @@ class ArpAgent < BaseAgent
70
81
  /[^\s]+\s+\(([0-9\.]+)\)\s+at\s+([a-f0-9:]+).+#{Context.get.ifconfig[:iface]}.*/i.match(line)
71
82
  end
72
83
 
73
- def send_probe( ip )
84
+ def get_probe( ip )
74
85
  pkt = PacketFu::ARPPacket.new
75
86
 
76
87
  pkt.eth_saddr = pkt.arp_saddr_mac = @ifconfig[:eth_saddr]
77
88
  pkt.eth_daddr = 'ff:ff:ff:ff:ff:ff'
78
89
  pkt.arp_daddr_mac = '00:00:00:00:00:00'
79
90
  pkt.arp_saddr_ip = @ifconfig[:ip_saddr]
80
- pkt.arp_daddr_ip = ip
91
+ pkt.arp_daddr_ip = ip.to_s
81
92
 
82
- pkt.to_w( @ifconfig[:iface] )
93
+ pkt
83
94
  end
84
95
  end
85
96
  end
97
+ end
98
+ end
@@ -12,72 +12,36 @@ This project is released under the GPL 3 license.
12
12
 
13
13
  # Base class for discovery agents.
14
14
  module BetterCap
15
- class BaseAgent
16
- def initialize( ifconfig, gw_ip, local_ip )
17
- @local_ip = local_ip
18
- @ifconfig = ifconfig
19
- @queue = Queue.new
15
+ module Discovery
16
+ module Agents
17
+ # Base class for BetterCap::Discovery::Agents.
18
+ class Base
19
+ # Initialize the agent using the +ctx+ BetterCap::Context instance.
20
+ def initialize( ctx )
21
+ @ctx = ctx
22
+ @ifconfig = ctx.ifconfig
23
+ @local_ip = @ifconfig[:ip_saddr]
20
24
 
21
25
  net = ip = @ifconfig[:ip4_obj]
22
-
23
26
  # loop each ip in our subnet and push it to the queue
24
27
  while net.include?ip
25
28
  # rescanning the gateway could cause an issue when the
26
29
  # gateway itself has multiple interfaces ( LAN, WAN ... )
27
- if ip != gw_ip and ip != local_ip
28
- @queue.push ip
30
+ if ip != ctx.gateway and ip != @local_ip
31
+ packet = get_probe(ip)
32
+ @ctx.packets.push(packet)
29
33
  end
30
34
 
31
35
  ip = ip.succ
32
36
  end
33
-
34
- # spawn the workers! ( tnx to https://blog.engineyard.com/2014/ruby-thread-pool )
35
- @workers = (0...4).map do
36
- Thread.new do
37
- begin
38
- while ip = @queue.pop(true)
39
- loop do
40
- Logger.debug "#{self.class.name} : Probing #{ip} ..."
41
-
42
- begin
43
- send_probe ip.to_s
44
-
45
- break
46
- rescue Exception => e
47
- Logger.debug "#{self.class.name}#send_probe : #{ip} -> #{e.message}"
48
-
49
- # If we've got an error message such as:
50
- # (cannot open BPF device) /dev/bpf0: Too many open files
51
- # We want to retry to probe this ip in a while.
52
- if e.message.include? 'Too many open files'
53
- Logger.debug "Retrying #{self.class.name}#send_probe on #{ip} in 1 second."
54
-
55
- sleep 1
56
- else
57
- break
58
- end
59
- end
60
- end
61
- end
62
- rescue Exception => e
63
- Logger.debug "#{self.class.name} : #{ip} -> #{e.message}"
64
- end
65
- end
66
- end
67
- end
68
-
69
- def wait
70
- begin
71
- @workers.map(&:join)
72
- rescue Exception => e
73
- Logger.debug "#{self.class.name}.wait: #{e.message}"
74
- end
75
37
  end
76
38
 
77
39
  private
78
40
 
79
- def send_probe( ip )
80
- Logger.warn "#{self.class.name} not implemented!"
41
+ def get_probe( ip )
42
+ Logger.warn "#{self.class.name}#get_probe not implemented!"
81
43
  end
82
44
  end
83
45
  end
46
+ end
47
+ end
@@ -12,25 +12,33 @@ This project is released under the GPL 3 license.
12
12
 
13
13
  # Send a broadcast ping trying to filling the ARP table.
14
14
  module BetterCap
15
- class IcmpAgent
16
- def initialize( timeout = 5 )
17
- @thread = Thread.new {
18
- FirewallFactory.get_firewall.enable_icmp_bcast(true)
19
-
20
- if RUBY_PLATFORM =~ /darwin/
21
- ping = Shell.execute("ping -i #{timeout} -c 2 255.255.255.255")
22
- elsif RUBY_PLATFORM =~ /linux/
23
- ping = Shell.execute("ping -i #{timeout} -c 2 -b 255.255.255.255 2> /dev/null")
24
- end
25
- }
26
- end
15
+ module Discovery
16
+ module Agents
17
+ # Class responsible to do a ping-sweep on the network.
18
+ class Icmp
19
+ # Create a thread which will perform a ping-sweep on the network in order
20
+ # to populate the ARP cache with active targets, with a +ctx.timeout+ seconds
21
+ # timeout.
22
+ def initialize( ctx )
23
+ Factories::Firewall.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.ifconfig[:eth_saddr]
30
+ pkt.eth_daddr = 'ff:ff:ff:ff:ff:ff'
31
+ pkt.ip_saddr = ctx.ifconfig[:ip_saddr]
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
27
37
 
28
- def wait
29
- begin
30
- @thread.join
31
- rescue Exception => e
32
- Logger.debug "IcmpAgent.wait: #{e.message}"
38
+ ctx.packets.push(pkt)
33
39
  end
34
40
  end
35
41
  end
36
42
  end
43
+ end
44
+ end
@@ -12,28 +12,17 @@ This project is released under the GPL 3 license.
12
12
 
13
13
  # Send UDP probes trying to filling the ARP table.
14
14
  module BetterCap
15
- class UdpAgent < BaseAgent
15
+ module Discovery
16
+ module Agents
17
+ # Class responsible to send UDP probe packets to each possible IP on the network.
18
+ class Udp < Discovery::Agents::Base
16
19
  private
17
20
 
18
- def send_probe( ip )
19
- port = 137
20
- message =
21
- "\x82\x28\x00\x00\x00" +
22
- "\x01\x00\x00\x00\x00" +
23
- "\x00\x00\x20\x43\x4B" +
24
- "\x41\x41\x41\x41\x41" +
25
- "\x41\x41\x41\x41\x41" +
26
- "\x41\x41\x41\x41\x41" +
27
- "\x41\x41\x41\x41\x41" +
28
- "\x41\x41\x41\x41\x41" +
29
- "\x41\x41\x41\x41\x41" +
30
- "\x00\x00\x21\x00\x01"
31
-
32
- # send netbios udp packet, just to fill ARP table
33
- sd = UDPSocket.new
34
- sd.send( message, 0, ip.to_s, port )
35
- sd = nil
36
- # TODO: Parse response for hostname?
21
+ def get_probe( ip )
22
+ # send dummy udp packet, just to fill ARP table
23
+ [ ip.to_s, 137, "\x10\x12\x85\x00\x00" ]
37
24
  end
38
25
  end
39
26
  end
27
+ end
28
+ end