bettercap 1.1.10 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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