bettercap 1.1.3 → 1.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +42 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +25 -0
- data/README.md +1 -1
- data/Rakefile +7 -0
- data/TODO.md +2 -2
- data/bettercap.gemspec +2 -0
- data/bin/bettercap +48 -43
- data/lib/bettercap/context.rb +125 -20
- data/lib/bettercap/factories/firewall_factory.rb +4 -0
- data/lib/bettercap/factories/parser_factory.rb +2 -0
- data/lib/bettercap/firewalls/linux.rb +16 -10
- data/lib/bettercap/firewalls/osx.rb +19 -8
- data/lib/bettercap/logger.rb +2 -0
- data/lib/bettercap/network.rb +10 -4
- data/lib/bettercap/proxy/certstore.rb +68 -0
- data/lib/bettercap/proxy/proxy.rb +87 -43
- data/lib/bettercap/proxy/request.rb +22 -4
- data/lib/bettercap/proxy/response.rb +15 -0
- data/lib/bettercap/sniffer/sniffer.rb +22 -24
- data/lib/bettercap/spoofers/arp.rb +38 -6
- data/lib/bettercap/target.rb +1 -1
- data/lib/bettercap/version.rb +1 -1
- data/lib/bettercap.rb +1 -0
- data/test/factories/firewall_factory_test.rb +54 -0
- data/test/factories/parser_factory_test.rb +36 -0
- data/test/factories/spoofer_factory_test.rb +15 -0
- data/test/firewalls/linux_firewall_test.rb +72 -0
- data/test/firewalls/osx_firewall_test.rb +72 -0
- data/test/helpers/mock_shell.rb +17 -0
- data/test/logger_test.rb +12 -0
- data/test/network_test.rb +14 -0
- data/test/pcap/ftp.pcap +0 -0
- data/test/pcap/http.pcap +0 -0
- data/test/pcap/packets.pcap +0 -0
- data/test/proxy/response_test.rb +56 -0
- data/test/shell_test.rb +15 -0
- data/test/sniffer/parsers/base_parser_test.rb +20 -0
- data/test/sniffer/parsers/ftp_parser_test.rb +27 -0
- data/test/sniffer/parsers/url_parser_test.rb +25 -0
- data/test/target_test.rb +24 -0
- data/test/test_helper.rb +47 -0
- data/test_https_proxy.rb +29 -0
- metadata +40 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0302105b4b7c6f181542e22fff7662fa6b4b922b
|
4
|
+
data.tar.gz: b46e666f283922dbe0bdb09fd6f2883dee7d89b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef42d62d1d051931e7b2ea84d56e09498e630628a1293bd3be5fc7a23d5457b57a2470896431171638bd59981ec0736a85847b359f592ca991ba378301831a34
|
7
|
+
data.tar.gz: ca6291a117033ab2139a616a7e8734fbf0bc5b05b57e25299b222bfceed8bcbc9785b148a988c4c059cfd4079d79b7f24d1cdfd76a439ce3c3b35f42d0c4a6d8
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# How To Contribute
|
2
|
+
|
3
|
+
As any other open source projects, there're many ways you can contribute to bettercap depending on your skills as a developer or will to help as a user, but first
|
4
|
+
of all let me thank you for your help! <3
|
5
|
+
|
6
|
+
### Submitting Issues
|
7
|
+
|
8
|
+
If you find bugs or inconsistencies while using bettercap, you can create an **Issue** using the [GitHub Issue tracker](https://github.com/evilsocket/bettercap/issues), but before doing that please make sure that:
|
9
|
+
|
10
|
+
* You are using a relatively new Ruby version ( >= 1.9 ) : `ruby -v`.
|
11
|
+
* Your GEM environment is configured properly and updated : `sudo gem update`.
|
12
|
+
* You are using the latest version of bettercap : `bettercap --check-updates`.
|
13
|
+
* The bug you're reporting is actually related to bettercap and not to one of the other GEMs.
|
14
|
+
|
15
|
+
Once you've gone through this list, open an issue and please give us as much as informations as possible in order for us to fix the bug as soon as possible:
|
16
|
+
|
17
|
+
* Your OS version.
|
18
|
+
* Ruby version you're using.
|
19
|
+
* Full output of the error ( exception backtrace, error message, etc ).
|
20
|
+
* Your network configuration: `ifconfig -a`
|
21
|
+
|
22
|
+
Also, you should attach to the issue a debug log that you can generate with:
|
23
|
+
|
24
|
+
sudo bettercap [arguments you are using for testing] --debug --log=debug.log
|
25
|
+
|
26
|
+
Wait for the error to happen then close bettercap and paste the **debug.log** file inside the issue.
|
27
|
+
|
28
|
+
### Pull Requests
|
29
|
+
|
30
|
+
If you know how to code in Ruby and have ideas to improve bettercap, you're very welcome to send us pull requests, we'll be happy to merge them whenever they comply to the following rules:
|
31
|
+
|
32
|
+
* You have at least manually tested your code, ideally you've created actual tests for it.
|
33
|
+
* Respect our coding standard, 2 spaces indentation and modular code.
|
34
|
+
* There're no conflicts with the current dev branch.
|
35
|
+
* Your commit messages are enough explanatory to us.
|
36
|
+
|
37
|
+
There're plenty of things you can to do improve the software:
|
38
|
+
|
39
|
+
* Implement a new proxy module and push it to the [dedicated repository](https://github.com/evilsocket/bettercap-proxy-modules).
|
40
|
+
* Implement a new [Spoofer module](https://github.com/evilsocket/bettercap/blob/master/lib/bettercap/spoofers/arp.rb).
|
41
|
+
* Implement a new [Sniffer credentials parser](https://github.com/evilsocket/bettercap/blob/master/lib/bettercap/sniffer/parsers/post.rb).
|
42
|
+
* Fix, extend or improve the core.
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
bettercap (1.1.3)
|
5
|
+
colorize (~> 0.7.5)
|
6
|
+
packetfu (~> 1.1.10)
|
7
|
+
pcaprub (~> 0.12.0)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
colorize (0.7.7)
|
13
|
+
minitest (5.7.0)
|
14
|
+
packetfu (1.1.10)
|
15
|
+
pcaprub (0.12.0)
|
16
|
+
|
17
|
+
PLATFORMS
|
18
|
+
ruby
|
19
|
+
|
20
|
+
DEPENDENCIES
|
21
|
+
bettercap!
|
22
|
+
minitest
|
23
|
+
|
24
|
+
BUNDLED WITH
|
25
|
+
1.10.3
|
data/README.md
CHANGED
data/Rakefile
ADDED
data/TODO.md
CHANGED
@@ -7,9 +7,8 @@ This is a list of TODOs I use to keep track of tasks and upcoming features.
|
|
7
7
|
- [x] BPF filters.
|
8
8
|
- [x] BeEF proxy module ( [BeefBOX](https://github.com/evilsocket/bettercap-proxy-modules/blob/master/beefbox.rb) ).
|
9
9
|
- [x] Use raw file arp parsing instead of "arp -a" to improve speed. ( Solved with arp -a -n )
|
10
|
+
- [x] sslmitm
|
10
11
|
- [ ] *BSD Support.
|
11
|
-
- [ ] sslstrip
|
12
|
-
- [ ] sslmitm
|
13
12
|
- [ ] HTTP/2 Support.
|
14
13
|
- [ ] Active packet filtering/injection/etc.
|
15
14
|
|
@@ -21,3 +20,4 @@ This is a list of TODOs I use to keep track of tasks and upcoming features.
|
|
21
20
|
- [ ] Windows Support? ( OMG PLZ NO! )
|
22
21
|
- [ ] Output/actions as json for UI integration?
|
23
22
|
- [ ] BeefBox / BeefDRONE with Raspberry PI?
|
23
|
+
- [ ] sslstrip ( not really sure, currently is quite useless )
|
data/bettercap.gemspec
CHANGED
data/bin/bettercap
CHANGED
@@ -32,7 +32,7 @@ begin
|
|
32
32
|
ctx.options[:spoofer] = v
|
33
33
|
end
|
34
34
|
|
35
|
-
opts.on( '-T', '--target
|
35
|
+
opts.on( '-T', '--target ADDRESS1,ADDRESS2', 'Target IP addresses, if not specified the whole subnet will be targeted.' ) do |v|
|
36
36
|
ctx.options[:target] = v
|
37
37
|
end
|
38
38
|
|
@@ -72,19 +72,40 @@ begin
|
|
72
72
|
ctx.options[:arpcache] = true
|
73
73
|
end
|
74
74
|
|
75
|
-
opts.on( '--no-spoofing', 'Disable spoofing, alias for --spoofer NONE.' ) do
|
75
|
+
opts.on( '--no-spoofing', 'Disable spoofing, alias for --spoofer NONE.' ) do
|
76
76
|
ctx.options[:spoofer] = 'NONE'
|
77
77
|
end
|
78
78
|
|
79
|
+
opts.on( '--half-duplex', 'Enable half-duplex MITM, this will make bettercap work in those cases when the router is not vulnerable.' ) do
|
80
|
+
ctx.options[:half_duplex] = true
|
81
|
+
end
|
82
|
+
|
79
83
|
opts.on( '--proxy', 'Enable HTTP proxy and redirects all HTTP requests to it, default to false.' ) do
|
80
84
|
ctx.options[:proxy] = true
|
81
85
|
end
|
82
86
|
|
87
|
+
opts.on( '--proxy-https', 'Enable HTTPS proxy and redirects all HTTPS requests to it, default to false.' ) do
|
88
|
+
ctx.options[:proxy] = true
|
89
|
+
ctx.options[:proxy_https] = true
|
90
|
+
end
|
91
|
+
|
83
92
|
opts.on( '--proxy-port PORT', 'Set HTTP proxy port, default to ' + ctx.options[:proxy_port].to_s + ' .' ) do |v|
|
84
93
|
ctx.options[:proxy] = true
|
85
94
|
ctx.options[:proxy_port] = v.to_i
|
86
95
|
end
|
87
96
|
|
97
|
+
opts.on( '--proxy-https-port PORT', 'Set HTTPS proxy port, default to ' + ctx.options[:proxy_https_port].to_s + ' .' ) do |v|
|
98
|
+
ctx.options[:proxy] = true
|
99
|
+
ctx.options[:proxy_https] = true
|
100
|
+
ctx.options[:proxy_https_port] = v.to_i
|
101
|
+
end
|
102
|
+
|
103
|
+
opts.on( '--proxy-pem FILE', 'Use a custom PEM certificate file for the HTTPS proxy.' ) do |v|
|
104
|
+
ctx.options[:proxy] = true
|
105
|
+
ctx.options[:proxy_https] = true
|
106
|
+
ctx.options[:proxy_pem_file] = File.expand_path v
|
107
|
+
end
|
108
|
+
|
88
109
|
opts.on( '--proxy-module MODULE', 'Ruby proxy module to load.' ) do |v|
|
89
110
|
ctx.options[:proxy] = true
|
90
111
|
ctx.options[:proxy_module] = File.expand_path v
|
@@ -132,17 +153,11 @@ begin
|
|
132
153
|
end.parse!
|
133
154
|
|
134
155
|
if ctx.options[:check_updates]
|
135
|
-
|
136
|
-
|
137
|
-
|
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
|
156
|
+
error_policy = lambda { |e|
|
157
|
+
Logger.error("Could not check for udpates: #{e.message}")
|
158
|
+
}
|
145
159
|
|
160
|
+
ctx.check_updates(error_policy)
|
146
161
|
exit
|
147
162
|
end
|
148
163
|
|
@@ -160,48 +175,36 @@ begin
|
|
160
175
|
|
161
176
|
ctx.start_discovery_thread
|
162
177
|
else
|
163
|
-
|
178
|
+
targets = ctx.options[:target].split(",")
|
179
|
+
valid_targets = targets.select { |target| Network.is_ip?(target) }
|
164
180
|
|
165
|
-
|
166
|
-
end
|
181
|
+
raise BetterCap::Error, "Invalid target" if valid_targets.empty?
|
167
182
|
|
168
|
-
|
183
|
+
invalid_targets = targets - valid_targets
|
184
|
+
invalid_targets.each do |target|
|
185
|
+
Logger.warn "Invalid target #{target}"
|
186
|
+
end
|
169
187
|
|
170
|
-
|
188
|
+
ctx.targets = valid_targets.map { |target| Target.new(target) }
|
189
|
+
end
|
171
190
|
|
172
|
-
Logger.debug "Module: #{ctx.options[:spoofer]}"
|
173
191
|
|
174
|
-
ctx.spoofer.
|
192
|
+
ctx.spoofer=Array.new
|
193
|
+
spoofer_modules_names=ctx.options[:spoofer].split(",")
|
194
|
+
spoofer_modules_names.each do |module_name|
|
195
|
+
Logger.info "Loading module : #{module_name}"
|
196
|
+
ctx.spoofer << SpooferFactory.get_by_name( module_name )
|
197
|
+
ctx.spoofer.last.start
|
198
|
+
end
|
175
199
|
|
176
200
|
if ctx.options[:proxy]
|
177
201
|
if ctx.options[:sniffer] and ( ctx.options[:parsers].include?'*' or ctx.options[:parsers].include?'URL' )
|
178
202
|
Logger.warn "WARNING: Both HTTP transparent proxy and URL parser are enabled, you're gonna see duplicated logs."
|
179
203
|
end
|
180
204
|
|
181
|
-
ctx.
|
182
|
-
|
183
|
-
if not ctx.options[:proxy_module].nil?
|
184
|
-
require ctx.options[:proxy_module]
|
185
|
-
|
186
|
-
Proxy::Module.register_modules
|
187
|
-
|
188
|
-
raise BetterCap::Error, "#{ctx.options[:proxy_module]} is not a valid bettercap proxy module." unless !Proxy::Module.modules.empty?
|
189
|
-
end
|
190
|
-
|
191
|
-
ctx.proxy = Proxy::Proxy.new( ctx.ifconfig[:ip_saddr], ctx.options[:proxy_port] ) do |request,response|
|
192
|
-
if Proxy::Module.modules.empty?
|
193
|
-
Logger.warn 'WARNING: No proxy module loaded, skipping request.'
|
194
|
-
else
|
195
|
-
# loop each loaded module and execute if enabled
|
196
|
-
Proxy::Module.modules.each do |mod|
|
197
|
-
if mod.enabled?
|
198
|
-
mod.on_request request, response
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
205
|
+
ctx.enable_port_redirection
|
203
206
|
|
204
|
-
ctx.
|
207
|
+
ctx.create_proxies
|
205
208
|
end
|
206
209
|
|
207
210
|
if ctx.options[:httpd]
|
@@ -212,7 +215,9 @@ begin
|
|
212
215
|
if ctx.options[:sniffer]
|
213
216
|
Sniffer.start ctx
|
214
217
|
else
|
215
|
-
|
218
|
+
if ctx.options[:spoofer] != 'NONE' and ctx.options[:spoofer] != 'none'
|
219
|
+
Logger.warn 'WARNING: Sniffer module was NOT enabled ( -X argument ), this will cause the MITM to run but no data to be collected.'
|
220
|
+
end
|
216
221
|
|
217
222
|
loop do
|
218
223
|
sleep 1
|
data/lib/bettercap/context.rb
CHANGED
@@ -18,7 +18,8 @@ require 'json'
|
|
18
18
|
|
19
19
|
class Context
|
20
20
|
attr_accessor :options, :ifconfig, :network, :firewall, :gateway,
|
21
|
-
:targets, :spoofer, :proxy, :httpd
|
21
|
+
:targets, :spoofer, :proxy, :https_proxy, :httpd,
|
22
|
+
:certificate
|
22
23
|
|
23
24
|
@@instance = nil
|
24
25
|
|
@@ -37,6 +38,7 @@ class Context
|
|
37
38
|
@options = {
|
38
39
|
iface: iface,
|
39
40
|
spoofer: 'ARP',
|
41
|
+
half_duplex: false,
|
40
42
|
target: nil,
|
41
43
|
logfile: nil,
|
42
44
|
debug: false,
|
@@ -49,7 +51,10 @@ class Context
|
|
49
51
|
local: false,
|
50
52
|
|
51
53
|
proxy: false,
|
54
|
+
proxy_https: false,
|
52
55
|
proxy_port: 8080,
|
56
|
+
proxy_https_port: 8083,
|
57
|
+
proxy_pem_file: nil,
|
53
58
|
proxy_module: nil,
|
54
59
|
|
55
60
|
httpd: false,
|
@@ -59,30 +64,49 @@ class Context
|
|
59
64
|
check_updates: false
|
60
65
|
}
|
61
66
|
|
62
|
-
@ifconfig
|
63
|
-
@network
|
64
|
-
@firewall
|
65
|
-
@gateway
|
66
|
-
@targets
|
67
|
-
@
|
68
|
-
@
|
69
|
-
@
|
67
|
+
@ifconfig = nil
|
68
|
+
@network = nil
|
69
|
+
@firewall = nil
|
70
|
+
@gateway = nil
|
71
|
+
@targets = []
|
72
|
+
@proxy_processor = nil
|
73
|
+
@proxy = nil
|
74
|
+
@https_proxy = nil
|
75
|
+
@spoofer = nil
|
76
|
+
@httpd = nil
|
77
|
+
@certificate = nil
|
70
78
|
|
71
79
|
@discovery_running = false
|
72
80
|
@discovery_thread = nil
|
73
81
|
end
|
74
82
|
|
75
|
-
def check_updates
|
83
|
+
def check_updates(error_policy = ->{ raise })
|
84
|
+
ver = get_latest_version
|
85
|
+
|
86
|
+
case ver
|
87
|
+
when BetterCap::VERSION
|
88
|
+
Logger.info 'You are running the latest version.'
|
89
|
+
else
|
90
|
+
Logger.warn "New version '#{ver}' available!"
|
91
|
+
end
|
92
|
+
rescue Exception => e
|
93
|
+
error_policy.call(e)
|
94
|
+
end
|
95
|
+
|
96
|
+
def get_latest_version
|
76
97
|
Logger.info 'Checking for updates ...'
|
77
98
|
|
78
|
-
api
|
79
|
-
|
80
|
-
json = JSON.parse(body)
|
99
|
+
api = URI('https://rubygems.org/api/v1/versions/bettercap/latest.json')
|
100
|
+
response = Net::HTTP.get_response(api)
|
81
101
|
|
82
|
-
|
83
|
-
|
102
|
+
case response
|
103
|
+
when Net::HTTPSuccess
|
104
|
+
json = JSON.parse(response.body)
|
105
|
+
else
|
106
|
+
raise response.message
|
84
107
|
end
|
85
|
-
|
108
|
+
|
109
|
+
return json['version']
|
86
110
|
end
|
87
111
|
|
88
112
|
def update_network
|
@@ -110,7 +134,12 @@ class Context
|
|
110
134
|
Logger.info 'Searching for alive targets ...'
|
111
135
|
else
|
112
136
|
# make sure we don't stress the logging system
|
113
|
-
|
137
|
+
10.times do
|
138
|
+
sleep 1
|
139
|
+
if !@discovery_running
|
140
|
+
break
|
141
|
+
end
|
142
|
+
end
|
114
143
|
end
|
115
144
|
|
116
145
|
@targets = Network.get_alive_targets self
|
@@ -139,17 +168,93 @@ class Context
|
|
139
168
|
end
|
140
169
|
end
|
141
170
|
|
171
|
+
def enable_port_redirection
|
172
|
+
Logger.info "Redirecting traffic from port 80 to #{@ifconfig[:ip_saddr]}:#{@options[:proxy_port]}"
|
173
|
+
|
174
|
+
@firewall.add_port_redirection( @options[:iface], 'TCP', 80, @ifconfig[:ip_saddr], @options[:proxy_port] )
|
175
|
+
if @options[:proxy_https]
|
176
|
+
Logger.info "Redirecting traffic from port 443 to #{@ifconfig[:ip_saddr]}:#{@options[:proxy_https_port]}"
|
177
|
+
|
178
|
+
@firewall.add_port_redirection( @options[:iface], 'TCP', 443, @ifconfig[:ip_saddr], @options[:proxy_https_port] )
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def disable_port_redirection
|
183
|
+
@firewall.del_port_redirection( @options[:iface], 'TCP', 80, @ifconfig[:ip_saddr], @options[:proxy_port] )
|
184
|
+
if @options[:proxy_https]
|
185
|
+
@firewall.del_port_redirection( @options[:iface], 'TCP', 443, @ifconfig[:ip_saddr], @options[:proxy_https_port] )
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def create_proxies
|
190
|
+
if not @options[:proxy_module].nil?
|
191
|
+
require @options[:proxy_module]
|
192
|
+
|
193
|
+
Proxy::Module.register_modules
|
194
|
+
|
195
|
+
raise BetterCap::Error, "#{@options[:proxy_module]} is not a valid bettercap proxy module." unless !Proxy::Module.modules.empty?
|
196
|
+
end
|
197
|
+
|
198
|
+
@proxy_processor = Proc.new do |request,response|
|
199
|
+
if Proxy::Module.modules.empty?
|
200
|
+
Logger.warn 'WARNING: No proxy module loaded, skipping request.'
|
201
|
+
else
|
202
|
+
# loop each loaded module and execute if enabled
|
203
|
+
Proxy::Module.modules.each do |mod|
|
204
|
+
if mod.enabled?
|
205
|
+
# we need to save the original response in case something
|
206
|
+
# in the module will go wrong
|
207
|
+
original = response
|
208
|
+
|
209
|
+
begin
|
210
|
+
mod.on_request request, response
|
211
|
+
rescue Exception => e
|
212
|
+
Logger.warn "Error with proxy module: #{e.message}"
|
213
|
+
response = original
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# create HTTP proxy
|
221
|
+
@proxy = Proxy::Proxy.new( @ifconfig[:ip_saddr], @options[:proxy_port], false, @proxy_processor )
|
222
|
+
@proxy.start
|
223
|
+
|
224
|
+
# create HTTPS proxy
|
225
|
+
if @options[:proxy_https]
|
226
|
+
# We're not acting as a normal HTTPS proxy, thus we're not
|
227
|
+
# able to handle CONNECT requests, thus we don't know the
|
228
|
+
# hostname the client is going to connect to.
|
229
|
+
# We can only use a self signed certificate.
|
230
|
+
if @options[:proxy_pem_file].nil?
|
231
|
+
@certificate = Proxy::CertStore.get_selfsigned
|
232
|
+
else
|
233
|
+
@certificate = Proxy::CertStore.from_file @options[:proxy_pem_file]
|
234
|
+
end
|
235
|
+
|
236
|
+
@https_proxy = Proxy::Proxy.new( @ifconfig[:ip_saddr], @options[:proxy_https_port], true, @proxy_processor )
|
237
|
+
@https_proxy.start
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
142
241
|
def finalize
|
143
242
|
stop_discovery_thread
|
144
243
|
|
145
244
|
# Consider !!@spoofer
|
146
|
-
|
147
|
-
|
245
|
+
|
246
|
+
if !@spoofer.nil? and @spoofer.length != 0
|
247
|
+
@spoofer.each do |itr|
|
248
|
+
itr.stop
|
249
|
+
end
|
148
250
|
end
|
149
251
|
|
150
252
|
if !@proxy.nil?
|
151
253
|
@proxy.stop
|
152
|
-
|
254
|
+
if !@https_proxy.nil?
|
255
|
+
@https_proxy.stop
|
256
|
+
end
|
257
|
+
disable_port_redirection
|
153
258
|
end
|
154
259
|
|
155
260
|
if !@firewall.nil?
|
@@ -14,34 +14,40 @@ require 'bettercap/shell'
|
|
14
14
|
|
15
15
|
class LinuxFirewall < IFirewall
|
16
16
|
def enable_forwarding(enabled)
|
17
|
-
|
17
|
+
shell.execute("echo #{enabled ? 1 : 0} > /proc/sys/net/ipv4/ip_forward")
|
18
18
|
end
|
19
19
|
|
20
20
|
def forwarding_enabled?
|
21
|
-
|
21
|
+
shell.execute('cat /proc/sys/net/ipv4/ip_forward').strip == '1'
|
22
22
|
end
|
23
23
|
|
24
24
|
def enable_icmp_bcast(enabled)
|
25
|
-
|
25
|
+
shell.execute("echo #{enabled ? 0 : 1} > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts")
|
26
26
|
end
|
27
27
|
|
28
28
|
def add_port_redirection( iface, proto, from, addr, to )
|
29
29
|
# clear nat
|
30
|
-
|
30
|
+
shell.execute('iptables -t nat -F')
|
31
31
|
# clear
|
32
|
-
|
32
|
+
shell.execute('iptables -F')
|
33
33
|
# post route
|
34
|
-
|
34
|
+
shell.execute('iptables -t nat -I POSTROUTING -s 0/0 -j MASQUERADE')
|
35
35
|
# accept all
|
36
|
-
|
36
|
+
shell.execute('iptables -P FORWARD ACCEPT')
|
37
37
|
# add redirection
|
38
|
-
|
38
|
+
shell.execute("iptables -t nat -A PREROUTING -i #{iface} -p #{proto} --dport #{from} -j REDIRECT --to #{to}")
|
39
39
|
end
|
40
40
|
|
41
41
|
def del_port_redirection( iface, proto, from, addr, to )
|
42
42
|
# remove post route
|
43
|
-
|
43
|
+
shell.execute('iptables -t nat -D POSTROUTING -s 0/0 -j MASQUERADE')
|
44
44
|
# remove redirection
|
45
|
-
|
45
|
+
shell.execute("iptables -t nat -D PREROUTING -i #{iface} -p #{proto} --dport #{from} -j REDIRECT --to #{to}")
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def shell
|
51
|
+
Shell
|
46
52
|
end
|
47
53
|
end
|
@@ -14,20 +14,20 @@ require 'bettercap/shell'
|
|
14
14
|
|
15
15
|
class OSXFirewall < IFirewall
|
16
16
|
def enable_forwarding(enabled)
|
17
|
-
|
17
|
+
shell.execute("sysctl -w net.inet.ip.forwarding=#{enabled ? 1 : 0}")
|
18
18
|
end
|
19
19
|
|
20
20
|
def enable_icmp_bcast(enabled)
|
21
|
-
|
21
|
+
shell.execute("sysctl -w net.inet.icmp.bmcastecho=#{enabled ? 1 : 0}")
|
22
22
|
end
|
23
23
|
|
24
24
|
def forwarding_enabled?
|
25
|
-
|
25
|
+
shell.execute('sysctl net.inet.ip.forwarding').strip.split(' ')[1] == '1'
|
26
26
|
end
|
27
27
|
|
28
28
|
def enable(enabled)
|
29
29
|
begin
|
30
|
-
|
30
|
+
shell.execute("pfctl -#{enabled ? 'e' : 'd'} >/dev/null 2>&1")
|
31
31
|
rescue; end
|
32
32
|
end
|
33
33
|
|
@@ -36,11 +36,11 @@ class OSXFirewall < IFirewall
|
|
36
36
|
config_file = "/tmp/bettercap_pf_#{Process.pid}.conf"
|
37
37
|
|
38
38
|
File.open( config_file, 'a+t' ) do |f|
|
39
|
-
f.write "rdr on #{iface}
|
39
|
+
f.write "rdr pass on #{iface} proto #{proto} from any to any port #{from} -> #{addr} port #{to}\n"
|
40
40
|
end
|
41
41
|
|
42
42
|
# load the rule
|
43
|
-
|
43
|
+
shell.execute("pfctl -f #{config_file} >/dev/null 2>&1")
|
44
44
|
# enable pf
|
45
45
|
enable true
|
46
46
|
end
|
@@ -51,7 +51,18 @@ class OSXFirewall < IFirewall
|
|
51
51
|
|
52
52
|
# disable pf
|
53
53
|
enable false
|
54
|
-
|
55
|
-
|
54
|
+
|
55
|
+
begin
|
56
|
+
# remove the pf config file
|
57
|
+
File.delete( "/tmp/bettercap_pf_#{Process.pid}.conf" )
|
58
|
+
rescue
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def shell
|
66
|
+
Shell
|
56
67
|
end
|
57
68
|
end
|
data/lib/bettercap/logger.rb
CHANGED
@@ -37,6 +37,7 @@ module Logger
|
|
37
37
|
# make sure that logging is thread safe
|
38
38
|
@@semaphore.synchronize {
|
39
39
|
puts message
|
40
|
+
|
40
41
|
if !@logfile.nil?
|
41
42
|
f = File.open( @logfile, 'a+t' )
|
42
43
|
f.puts( message.gsub( /\e\[(\d+)(;\d+)*m/, '') + "\n")
|
@@ -46,6 +47,7 @@ module Logger
|
|
46
47
|
end
|
47
48
|
|
48
49
|
private
|
50
|
+
|
49
51
|
def formatted_message(message, message_type)
|
50
52
|
"[#{message_type}] #{message}"
|
51
53
|
end
|
data/lib/bettercap/network.rb
CHANGED
@@ -24,7 +24,7 @@ require 'bettercap/discovery/arp'
|
|
24
24
|
class Network
|
25
25
|
class << self
|
26
26
|
def is_ip?(ip)
|
27
|
-
if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ ip
|
27
|
+
if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ ip.to_s
|
28
28
|
return $~.captures.all? {|i| i.to_i < 256}
|
29
29
|
end
|
30
30
|
false
|
@@ -39,12 +39,18 @@ class Network
|
|
39
39
|
gw = nil
|
40
40
|
out.each do |line|
|
41
41
|
if line.include?( Context.get.options[:iface] )
|
42
|
-
|
43
|
-
|
42
|
+
tmp = line.split[1]
|
43
|
+
if is_ip?(tmp)
|
44
|
+
gw = tmp
|
45
|
+
break
|
46
|
+
end
|
44
47
|
end
|
45
48
|
end
|
46
49
|
|
47
|
-
raise BetterCap::Error,
|
50
|
+
raise BetterCap::Error, "Could not detect the gateway address for interface #{Context.get.options[:iface]}, "\
|
51
|
+
'make sure you\'ve specified the correct network interface to use and to have the '\
|
52
|
+
'correct network configuration, this could also happen if bettercap '\
|
53
|
+
'is launched from a virtual environment.' unless !gw.nil? and is_ip?(gw)
|
48
54
|
gw
|
49
55
|
end
|
50
56
|
|