bettercap 1.1.2 → 1.1.3

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