bettercap 1.1.7 → 1.1.8
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 +4 -4
- data/.gitignore +3 -1
- data/README.md +18 -14
- data/TODO.md +11 -4
- data/bettercap.gemspec +1 -0
- data/bin/bettercap +75 -112
- data/lib/bettercap.rb +1 -0
- data/lib/bettercap/context.rb +48 -114
- data/lib/bettercap/discovery/arp.rb +32 -22
- data/lib/bettercap/network.rb +3 -3
- data/lib/bettercap/options.rb +189 -0
- data/lib/bettercap/proxy/proxy.rb +9 -8
- data/lib/bettercap/proxy/request.rb +1 -1
- data/lib/bettercap/proxy/response.rb +10 -2
- data/lib/bettercap/proxy/stream_logger.rb +11 -6
- data/lib/bettercap/proxy/streamer.rb +67 -15
- data/lib/bettercap/proxy/thread_pool.rb +0 -64
- data/lib/bettercap/sniffer/parsers/base.rb +7 -1
- data/lib/bettercap/sniffer/parsers/httpauth.rb +4 -5
- data/lib/bettercap/sniffer/parsers/https.rb +1 -1
- data/lib/bettercap/sniffer/parsers/ntlmss.rb +1 -1
- data/lib/bettercap/sniffer/parsers/post.rb +1 -1
- data/lib/bettercap/sniffer/parsers/url.rb +1 -1
- data/lib/bettercap/sniffer/sniffer.rb +10 -10
- data/lib/bettercap/spoofers/arp.rb +12 -17
- data/lib/bettercap/target.rb +47 -5
- data/lib/bettercap/version.rb +1 -1
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 851e88dcce552dfe264421c42fd1ad02c4ef0160
|
4
|
+
data.tar.gz: 25e6d2a981d6113e86c150f833405c417594d613
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d58eeb378e71ed4ef0059f5380763a4559d3c7f17d80da9ef54c415b760cfe47e38f52a9ea2cd2ba282ff326e87441c0b863790fa5b5b5b07ac0dd282246f3d
|
7
|
+
data.tar.gz: d19bc791b7cedf8f64527a981f248dd9c5b35ce1c8937df7cf1878f97c1ca0c79722c91f7c914968e288a34c798c22b385d070daa9bea686861844a1904d4ab9
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|

|
2
2
|
|
3
|
-
Copyleft of Simone '[evilsocket](https://twitter.com/evilsocket)' Margaritelli*.
|
4
|
-
|
5
3
|
http://www.bettercap.org/
|
6
4
|
|
7
5
|
[](http://badge.fury.io/rb/bettercap) [](https://codeclimate.com/github/evilsocket/bettercap)
|
@@ -10,32 +8,38 @@ http://www.bettercap.org/
|
|
10
8
|
**bettercap** is a complete, modular, portable and easily extensible **MITM** tool and framework with every kind of diagnostic
|
11
9
|
and offensive feature you could need in order to perform a man in the middle attack.
|
12
10
|
|
13
|
-
|
14
|
-
|
11
|
+
Contact me at:
|
12
|
+
|
13
|
+
- Twitter: [@evilsocket](https://twitter.com/evilsocket)
|
14
|
+
- Email: evilsocket@gmail.com
|
15
|
+
|
16
|
+
Before submitting issues, please read the relevant [section](http://www.bettercap.org/docs/contribute/) in the documentation.
|
17
|
+
|
18
|
+
Installation
|
19
|
+
============
|
15
20
|
|
16
21
|
**Stable Release ( GEM )**
|
17
|
-
|
22
|
+
|
18
23
|
gem install bettercap
|
19
|
-
|
24
|
+
|
20
25
|
**From Source**
|
21
|
-
|
26
|
+
|
22
27
|
git clone https://github.com/evilsocket/bettercap
|
23
28
|
cd bettercap
|
24
29
|
gem build bettercap.gemspec
|
25
30
|
sudo gem install bettercap*.gem
|
26
31
|
|
27
|
-
|
28
|
-
|
32
|
+
Dependencies
|
33
|
+
============
|
29
34
|
|
30
35
|
All dependencies will be automatically installed through the GEM system, in some case you might need to install some system
|
31
36
|
dependency in order to make everything work:
|
32
37
|
|
33
38
|
sudo apt-get install ruby-dev libpcap-dev
|
34
|
-
|
35
|
-
This should solve issues such as [this one](https://github.com/evilsocket/bettercap/issues/22).
|
36
39
|
|
40
|
+
This should solve issues such as [this one](https://github.com/evilsocket/bettercap/issues/22).
|
37
41
|
|
38
|
-
|
39
|
-
|
42
|
+
Documentation and Examples
|
43
|
+
============
|
40
44
|
|
41
|
-
Please refer to the [official website](http://bettercap.org).
|
45
|
+
Please refer to the [official website](http://www.bettercap.org/docs/).
|
data/TODO.md
CHANGED
@@ -3,15 +3,22 @@ This is a list of TODOs I use to keep track of tasks and upcoming features.
|
|
3
3
|
---
|
4
4
|
|
5
5
|
- [x] Implement `--ignore ADDR,ADDR,ADDR` option to filter out specific addresses from the targets list.
|
6
|
+
- [x] HTTP 1.1 chunked response support.
|
7
|
+
- [x] Ip address to hostname resolution.
|
8
|
+
- [ ] Implement event-driven core plugin infrastructure ( for webui, etc ).
|
9
|
+
- [ ] Implement web-ui core plugin.
|
6
10
|
- [ ] Rewrite proxy class using [em-proxy](https://github.com/igrigorik/em-proxy) library.
|
7
|
-
- [ ] [Active packet filtering/injection/etc](https://github.com/evilsocket/bettercap/issues/75) ( maybe using [this](https://github.com/gdelugre/ruby-nfqueue) ).
|
8
|
-
- [ ] *BSD Support.
|
9
11
|
- [ ] HTTP/2 Support.
|
12
|
+
- [ ] IPV6 Support.
|
13
|
+
|
14
|
+
**Platform Specific**
|
15
|
+
|
16
|
+
- [ ] *BSD Support.
|
17
|
+
- [ ] Windows Support? ( OMG PLZ NO! )
|
18
|
+
- [ ] GNU/Linux [Active packet filtering/injection/etc](https://github.com/evilsocket/bettercap/issues/75) ( maybe using [this](https://github.com/gdelugre/ruby-nfqueue) ).
|
10
19
|
|
11
20
|
**Maybe**
|
12
21
|
|
13
22
|
- [ ] ICMP Redirect ? ( only half duplex and filtered by many firewalls anyway ... dunno ).
|
14
23
|
- [ ] DNS Spoofing ( not sure if it actually makes any sense ).
|
15
|
-
- [ ] Windows Support? ( OMG PLZ NO! )
|
16
|
-
- [ ] Output/actions as json for UI integration?
|
17
24
|
- [ ] sslstrip ( not really sure, currently is quite useless )
|
data/bettercap.gemspec
CHANGED
@@ -16,6 +16,7 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.add_dependency( 'colorize', '~> 0.7.5' )
|
17
17
|
gem.add_dependency( 'packetfu', '~> 1.1.10' )
|
18
18
|
gem.add_dependency( 'pcaprub', '~> 0.12.0' )
|
19
|
+
gem.add_dependency( 'network_interface', '~> 0.0.1' )
|
19
20
|
|
20
21
|
gem.add_development_dependency( 'minitest' )
|
21
22
|
|
data/bin/bettercap
CHANGED
@@ -23,149 +23,149 @@ begin
|
|
23
23
|
OptionParser.new do |opts|
|
24
24
|
opts.banner = "Usage: #{$0} [options]"
|
25
25
|
opts.version = BetterCap::VERSION
|
26
|
-
|
26
|
+
|
27
27
|
opts.on( '-G', '--gateway ADDRESS', 'Manually specify the gateway address, if not specified the current gateway will be retrieved and used. ' ) do |v|
|
28
|
-
ctx.options
|
28
|
+
ctx.options.gateway = v
|
29
29
|
end
|
30
30
|
|
31
|
-
opts.on( '-I', '--interface IFACE', 'Network interface name - default: ' + ctx.options
|
32
|
-
ctx.options
|
31
|
+
opts.on( '-I', '--interface IFACE', 'Network interface name - default: ' + ctx.options.iface.to_s ) do |v|
|
32
|
+
ctx.options.iface = v
|
33
33
|
end
|
34
34
|
|
35
|
-
opts.on( '-S', '--spoofer NAME', 'Spoofer module to use, available: ' + SpooferFactory.available.join(', ') + ' - default: ' + ctx.options
|
36
|
-
ctx.options
|
35
|
+
opts.on( '-S', '--spoofer NAME', 'Spoofer module to use, available: ' + SpooferFactory.available.join(', ') + ' - default: ' + ctx.options.spoofer ) do |v|
|
36
|
+
ctx.options.spoofer = v
|
37
37
|
end
|
38
38
|
|
39
39
|
opts.on( '-T', '--target ADDRESS1,ADDRESS2', 'Target IP addresses, if not specified the whole subnet will be targeted.' ) do |v|
|
40
|
-
ctx.options
|
40
|
+
ctx.options.target = v
|
41
41
|
end
|
42
42
|
|
43
43
|
opts.on( '--ignore ADDRESS1,ADDRESS2', 'Ignore these addresses if found while searching for targets.' ) do |v|
|
44
|
-
ctx.options
|
44
|
+
ctx.options.ignore = v
|
45
45
|
end
|
46
46
|
|
47
47
|
opts.on( '-O', '--log LOG_FILE', 'Log all messages into a file, if not specified the log messages will be only print into the shell.' ) do |v|
|
48
|
-
ctx.options
|
48
|
+
ctx.options.logfile = v
|
49
49
|
end
|
50
50
|
|
51
51
|
opts.on( '-D', '--debug', 'Enable debug logging.' ) do
|
52
|
-
ctx.options
|
52
|
+
ctx.options.debug = true
|
53
53
|
end
|
54
54
|
|
55
55
|
opts.on( '-L', '--local', 'Parse packets coming from/to the address of this computer ( NOTE: Will set -X to true ), default to false.' ) do
|
56
|
-
ctx.options
|
57
|
-
ctx.options
|
56
|
+
ctx.options.local = true
|
57
|
+
ctx.options.sniffer = true
|
58
58
|
end
|
59
59
|
|
60
60
|
opts.on( '-X', '--sniffer', 'Enable sniffer.' ) do
|
61
|
-
ctx.options
|
61
|
+
ctx.options.sniffer = true
|
62
62
|
end
|
63
63
|
|
64
64
|
opts.on( '--sniffer-source FILE', 'Load packets from the specified PCAP file instead of the interface ( will enable sniffer ).' ) do |v|
|
65
|
-
ctx.options
|
66
|
-
ctx.options
|
65
|
+
ctx.options.sniffer = true
|
66
|
+
ctx.options.sniffer_src = File.expand_path v
|
67
67
|
end
|
68
68
|
|
69
69
|
opts.on( '--sniffer-pcap FILE', 'Save all packets to the specified PCAP file ( will enable sniffer ).' ) do |v|
|
70
|
-
ctx.options
|
71
|
-
ctx.options
|
70
|
+
ctx.options.sniffer = true
|
71
|
+
ctx.options.sniffer_pcap = File.expand_path v
|
72
72
|
end
|
73
73
|
|
74
74
|
opts.on( '--sniffer-filter EXPRESSION', 'Configure the sniffer to use this BPF filter ( will enable sniffer ).' ) do |v|
|
75
|
-
ctx.options
|
76
|
-
ctx.options
|
75
|
+
ctx.options.sniffer = true
|
76
|
+
ctx.options.sniffer_filter = v
|
77
77
|
end
|
78
78
|
|
79
79
|
opts.on( '-P', '--parsers PARSERS', 'Comma separated list of packet parsers to enable, "*" for all ( NOTE: Will set -X to true ), available: ' + ParserFactory.available.join(', ') + ' - default: *' ) do |v|
|
80
|
-
ctx.options
|
81
|
-
ctx.options
|
80
|
+
ctx.options.sniffer = true
|
81
|
+
ctx.options.parsers = ParserFactory.from_cmdline(v)
|
82
82
|
end
|
83
83
|
|
84
84
|
opts.on( '--no-discovery', 'Do not actively search for hosts, just use the current ARP cache, default to false.' ) do
|
85
|
-
ctx.options
|
85
|
+
ctx.options.arpcache = true
|
86
86
|
end
|
87
87
|
|
88
88
|
opts.on( '--no-spoofing', 'Disable spoofing, alias for --spoofer NONE.' ) do
|
89
|
-
ctx.options
|
89
|
+
ctx.options.spoofer = 'NONE'
|
90
90
|
end
|
91
91
|
|
92
92
|
opts.on( '--half-duplex', 'Enable half-duplex MITM, this will make bettercap work in those cases when the router is not vulnerable.' ) do
|
93
|
-
ctx.options
|
93
|
+
ctx.options.half_duplex = true
|
94
94
|
end
|
95
95
|
|
96
96
|
opts.on( '--proxy', 'Enable HTTP proxy and redirects all HTTP requests to it, default to false.' ) do
|
97
|
-
ctx.options
|
97
|
+
ctx.options.proxy = true
|
98
98
|
end
|
99
99
|
|
100
100
|
opts.on( '--proxy-https', 'Enable HTTPS proxy and redirects all HTTPS requests to it, default to false.' ) do
|
101
|
-
ctx.options
|
102
|
-
ctx.options
|
101
|
+
ctx.options.proxy = true
|
102
|
+
ctx.options.proxy_https = true
|
103
103
|
end
|
104
104
|
|
105
|
-
opts.on( '--proxy-port PORT', 'Set HTTP proxy port, default to ' + ctx.options
|
106
|
-
ctx.options
|
107
|
-
ctx.options
|
105
|
+
opts.on( '--proxy-port PORT', 'Set HTTP proxy port, default to ' + ctx.options.proxy_port.to_s + ' .' ) do |v|
|
106
|
+
ctx.options.proxy = true
|
107
|
+
ctx.options.proxy_port = v.to_i
|
108
108
|
end
|
109
109
|
|
110
|
-
opts.on( '--proxy-https-port PORT', 'Set HTTPS proxy port, default to ' + ctx.options
|
111
|
-
ctx.options
|
112
|
-
ctx.options
|
113
|
-
ctx.options
|
110
|
+
opts.on( '--proxy-https-port PORT', 'Set HTTPS proxy port, default to ' + ctx.options.proxy_https_port.to_s + ' .' ) do |v|
|
111
|
+
ctx.options.proxy = true
|
112
|
+
ctx.options.proxy_https = true
|
113
|
+
ctx.options.proxy_https_port = v.to_i
|
114
114
|
end
|
115
115
|
|
116
116
|
opts.on( '--proxy-pem FILE', 'Use a custom PEM certificate file for the HTTPS proxy.' ) do |v|
|
117
|
-
ctx.options
|
118
|
-
ctx.options
|
119
|
-
ctx.options
|
117
|
+
ctx.options.proxy = true
|
118
|
+
ctx.options.proxy_https = true
|
119
|
+
ctx.options.proxy_pem_file = File.expand_path v
|
120
120
|
end
|
121
121
|
|
122
122
|
opts.on( '--proxy-module MODULE', 'Ruby proxy module to load.' ) do |v|
|
123
|
-
ctx.options
|
124
|
-
ctx.options
|
123
|
+
ctx.options.proxy = true
|
124
|
+
ctx.options.proxy_module = File.expand_path v
|
125
125
|
end
|
126
126
|
|
127
127
|
opts.on( '--custom-proxy ADDRESS', 'Use a custom HTTP upstream proxy instead of the builtin one.' ) do |v|
|
128
|
-
ctx.options
|
128
|
+
ctx.options.custom_proxy = v
|
129
129
|
end
|
130
130
|
|
131
|
-
opts.on( '--custom-proxy-port PORT', 'Specify a port for the custom HTTP upstream proxy, default to ' + ctx.options
|
132
|
-
ctx.options
|
131
|
+
opts.on( '--custom-proxy-port PORT', 'Specify a port for the custom HTTP upstream proxy, default to ' + ctx.options.custom_proxy_port.to_s + ' .' ) do |v|
|
132
|
+
ctx.options.custom_proxy_port = v.to_i
|
133
133
|
end
|
134
134
|
|
135
135
|
opts.on( '--custom-https-proxy ADDRESS', 'Use a custom HTTPS upstream proxy instead of the builtin one.' ) do |v|
|
136
|
-
ctx.options
|
136
|
+
ctx.options.custom_https_proxy = v
|
137
137
|
end
|
138
138
|
|
139
|
-
opts.on( '--custom-https-proxy-port PORT', 'Specify a port for the custom HTTPS upstream proxy, default to ' + ctx.options
|
140
|
-
ctx.options
|
139
|
+
opts.on( '--custom-https-proxy-port PORT', 'Specify a port for the custom HTTPS upstream proxy, default to ' + ctx.options.custom_https_proxy_port.to_s + ' .' ) do |v|
|
140
|
+
ctx.options.custom_https_proxy_port = v.to_i
|
141
141
|
end
|
142
142
|
|
143
143
|
opts.on( '--httpd', 'Enable HTTP server, default to false.' ) do
|
144
|
-
ctx.options
|
144
|
+
ctx.options.httpd = true
|
145
145
|
end
|
146
146
|
|
147
|
-
opts.on( '--httpd-port PORT', 'Set HTTP server port, default to ' + ctx.options
|
148
|
-
ctx.options
|
149
|
-
ctx.options
|
147
|
+
opts.on( '--httpd-port PORT', 'Set HTTP server port, default to ' + ctx.options.httpd_port.to_s + '.' ) do |v|
|
148
|
+
ctx.options.httpd = true
|
149
|
+
ctx.options.httpd_port = v.to_i
|
150
150
|
end
|
151
151
|
|
152
|
-
opts.on( '--httpd-path PATH', 'Set HTTP server path, default to ' + ctx.options
|
153
|
-
ctx.options
|
154
|
-
ctx.options
|
152
|
+
opts.on( '--httpd-path PATH', 'Set HTTP server path, default to ' + ctx.options.httpd_path + '.' ) do |v|
|
153
|
+
ctx.options.httpd = true
|
154
|
+
ctx.options.httpd_path = v
|
155
155
|
end
|
156
156
|
|
157
157
|
opts.on( '--check-updates', 'Will check if any update is available and then exit.' ) do
|
158
|
-
ctx.options
|
158
|
+
ctx.options.check_updates = true
|
159
159
|
end
|
160
160
|
|
161
161
|
opts.on('-h', '--help', 'Display the available options.') do
|
162
162
|
puts opts
|
163
|
-
puts "\nFor examples &
|
163
|
+
puts "\nFor examples & docs please visit " + "http://bettercap.org/docs/".bold
|
164
164
|
exit
|
165
165
|
end
|
166
166
|
end.parse!
|
167
167
|
|
168
|
-
if ctx.options
|
168
|
+
if ctx.options.check_updates
|
169
169
|
error_policy = lambda { |e|
|
170
170
|
Logger.error("Could not check for udpates: #{e.message}")
|
171
171
|
}
|
@@ -175,90 +175,53 @@ begin
|
|
175
175
|
end
|
176
176
|
|
177
177
|
raise BetterCap::Error, 'This software must run as root.' unless Process.uid == 0
|
178
|
-
raise BetterCap::Error, 'No default interface found, please specify one with the -I argument.' unless !ctx.options
|
178
|
+
raise BetterCap::Error, 'No default interface found, please specify one with the -I argument.' unless !ctx.options.iface.nil?
|
179
179
|
|
180
|
-
Logger.debug_enabled = true unless !ctx.options
|
180
|
+
Logger.debug_enabled = true unless !ctx.options.debug
|
181
181
|
|
182
|
-
Logger.logfile = ctx.options
|
182
|
+
Logger.logfile = ctx.options.logfile
|
183
183
|
|
184
184
|
|
185
|
-
|
186
|
-
raise BetterCap::Error, "Invalid gateway" if !Network.is_ip?(ctx.options
|
187
|
-
ctx.gateway = ctx.options
|
185
|
+
unless ctx.options.gateway.nil?
|
186
|
+
raise BetterCap::Error, "Invalid gateway" if !Network.is_ip?(ctx.options.gateway)
|
187
|
+
ctx.gateway = ctx.options.gateway
|
188
188
|
Logger.info("Targetting manual gateway #{ctx.gateway}")
|
189
189
|
end
|
190
|
-
|
190
|
+
|
191
191
|
ctx.update_network
|
192
192
|
|
193
|
-
if ctx.options
|
194
|
-
Logger.info( "Targeting the whole subnet #{ctx.network.to_range} ..." ) unless
|
195
|
-
ctx.options[:spoofer] == 'NONE' or ctx.options[:spoofer] == 'none'
|
193
|
+
if ctx.options.target.nil?
|
194
|
+
Logger.info( "Targeting the whole subnet #{ctx.network.to_range} ..." ) unless ctx.options.has_spoofer?
|
196
195
|
|
197
196
|
ctx.start_discovery_thread
|
198
197
|
else
|
199
|
-
targets = ctx.options
|
200
|
-
valid_targets = targets.select { |target| Network.is_ip?(target) }
|
201
|
-
|
202
|
-
raise BetterCap::Error, "Invalid target" if valid_targets.empty?
|
203
|
-
|
204
|
-
invalid_targets = targets - valid_targets
|
205
|
-
invalid_targets.each do |target|
|
206
|
-
Logger.warn "Invalid target #{target}"
|
207
|
-
end
|
208
|
-
|
209
|
-
ctx.targets = valid_targets.map { |target| Target.new(target) }
|
210
|
-
end
|
211
|
-
|
212
|
-
unless ctx.options[:ignore].nil?
|
213
|
-
ignore = ctx.options[:ignore].split(",")
|
214
|
-
valid = ignore.select { |target| Network.is_ip?(target) }
|
215
|
-
|
216
|
-
raise BetterCap::Error, "Invalid ignore addresses specified." if valid.empty?
|
217
|
-
|
218
|
-
invalid = ignore - valid
|
219
|
-
invalid.each do |target|
|
220
|
-
Logger.warn "Not a valid address: #{target}"
|
221
|
-
end
|
222
|
-
|
223
|
-
ctx.options[:ignore] = valid
|
224
|
-
|
225
|
-
Logger.warn "Ignoring #{valid.join(", ")} ."
|
198
|
+
ctx.targets = ctx.options.to_targets
|
226
199
|
end
|
227
200
|
|
228
|
-
ctx.spoofer =
|
229
|
-
|
230
|
-
|
231
|
-
ctx.spoofer << SpooferFactory.get_by_name( module_name )
|
232
|
-
ctx.spoofer.last.start
|
201
|
+
ctx.spoofer = ctx.options.to_spoofers
|
202
|
+
ctx.spoofer.each do |spoofer|
|
203
|
+
spoofer.start
|
233
204
|
end
|
234
205
|
|
235
|
-
if ctx.options
|
236
|
-
if ctx.options
|
206
|
+
if ctx.options.proxy
|
207
|
+
if ctx.options.has_http_sniffer_enabled?
|
237
208
|
Logger.warn "WARNING: Both HTTP transparent proxy and URL parser are enabled, you're gonna see duplicated logs."
|
238
209
|
end
|
239
210
|
|
240
211
|
ctx.create_proxies
|
241
212
|
end
|
242
213
|
|
243
|
-
if ctx.options[:custom_proxy]
|
244
|
-
raise BetterCap::Error, 'Invalid custom HTTP upstream proxy address specified.' unless Network.is_ip? ctx.options[:custom_proxy]
|
245
|
-
end
|
246
|
-
|
247
|
-
if ctx.options[:custom_https_proxy]
|
248
|
-
raise BetterCap::Error, 'Invalid custom HTTPS upstream proxy address specified.' unless Network.is_ip? ctx.options[:custom_https_proxy]
|
249
|
-
end
|
250
|
-
|
251
214
|
ctx.enable_port_redirection
|
252
|
-
|
253
|
-
if ctx.options
|
254
|
-
ctx.httpd = HTTPD::Server.new( ctx.options
|
215
|
+
|
216
|
+
if ctx.options.httpd
|
217
|
+
ctx.httpd = HTTPD::Server.new( ctx.options.httpd_port, ctx.options.httpd_path )
|
255
218
|
ctx.httpd.start
|
256
219
|
end
|
257
220
|
|
258
|
-
if ctx.options
|
221
|
+
if ctx.options.sniffer
|
259
222
|
Sniffer.start ctx
|
260
223
|
else
|
261
|
-
|
224
|
+
unless ctx.options.has_spoofer?
|
262
225
|
Logger.warn 'WARNING: Sniffer module was NOT enabled ( -X argument ), this will cause the MITM to run but no data to be collected.'
|
263
226
|
end
|
264
227
|
|
data/lib/bettercap.rb
CHANGED
data/lib/bettercap/context.rb
CHANGED
@@ -18,7 +18,7 @@ require 'json'
|
|
18
18
|
|
19
19
|
class Context
|
20
20
|
attr_accessor :options, :ifconfig, :network, :firewall, :gateway,
|
21
|
-
:targets, :spoofer, :
|
21
|
+
:targets, :spoofer, :httpd,
|
22
22
|
:certificate
|
23
23
|
|
24
24
|
@@instance = nil
|
@@ -35,58 +35,18 @@ class Context
|
|
35
35
|
Logger.debug e.message
|
36
36
|
end
|
37
37
|
|
38
|
-
@options
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
sniffer: false,
|
51
|
-
sniffer_pcap: nil,
|
52
|
-
sniffer_filter: nil,
|
53
|
-
sniffer_src: nil,
|
54
|
-
parsers: ['*'],
|
55
|
-
local: false,
|
56
|
-
|
57
|
-
proxy: false,
|
58
|
-
proxy_https: false,
|
59
|
-
proxy_port: 8080,
|
60
|
-
proxy_https_port: 8083,
|
61
|
-
proxy_pem_file: nil,
|
62
|
-
proxy_module: nil,
|
63
|
-
|
64
|
-
custom_proxy: nil,
|
65
|
-
custom_proxy_port: 8080,
|
66
|
-
|
67
|
-
custom_https_proxy: nil,
|
68
|
-
custom_https_proxy_port: 8083,
|
69
|
-
|
70
|
-
httpd: false,
|
71
|
-
httpd_port: 8081,
|
72
|
-
httpd_path: './',
|
73
|
-
|
74
|
-
check_updates: false
|
75
|
-
}
|
76
|
-
|
77
|
-
@ifconfig = nil
|
78
|
-
@network = nil
|
79
|
-
@firewall = nil
|
80
|
-
@gateway = nil
|
81
|
-
@targets = []
|
82
|
-
@proxy_processor = nil
|
83
|
-
@proxy = nil
|
84
|
-
@https_proxy = nil
|
85
|
-
@spoofer = nil
|
86
|
-
@httpd = nil
|
87
|
-
@certificate = nil
|
88
|
-
@redirections = []
|
89
|
-
|
38
|
+
@options = Options.new iface
|
39
|
+
@ifconfig = nil
|
40
|
+
@network = nil
|
41
|
+
@firewall = nil
|
42
|
+
@gateway = nil
|
43
|
+
@targets = []
|
44
|
+
@proxy_processor = nil
|
45
|
+
@spoofer = nil
|
46
|
+
@httpd = nil
|
47
|
+
@certificate = nil
|
48
|
+
@proxies = []
|
49
|
+
@redirections = []
|
90
50
|
@discovery_running = false
|
91
51
|
@discovery_thread = nil
|
92
52
|
end
|
@@ -122,25 +82,34 @@ class Context
|
|
122
82
|
|
123
83
|
def update_network
|
124
84
|
@firewall = FirewallFactory.get_firewall
|
125
|
-
@ifconfig = PacketFu::Utils.ifconfig @options
|
85
|
+
@ifconfig = PacketFu::Utils.ifconfig @options.iface
|
126
86
|
@network = @ifconfig[:ip4_obj]
|
127
87
|
@gateway = Network.get_gateway if @gateway.nil?
|
128
88
|
|
129
|
-
raise BetterCap::Error, "Could not determine IPv4 address of '#{@options
|
89
|
+
raise BetterCap::Error, "Could not determine IPv4 address of '#{@options.iface}' interface." unless !@network.nil?
|
130
90
|
|
131
91
|
Logger.debug "network=#{@network} gateway=#{@gateway} local_ip=#{@ifconfig[:ip_saddr]}"
|
132
92
|
Logger.debug "IFCONFIG: #{@ifconfig.inspect}"
|
133
93
|
end
|
134
94
|
|
95
|
+
def find_target ip, mac
|
96
|
+
@targets.each do |target|
|
97
|
+
if target.ip == ip && ( mac.nil? || target.mac == mac )
|
98
|
+
return target
|
99
|
+
end
|
100
|
+
end
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
|
135
104
|
def start_discovery_thread
|
136
105
|
@discovery_running = true
|
137
106
|
@discovery_thread = Thread.new {
|
138
|
-
Logger.info( 'Network discovery thread started.' ) unless @options
|
107
|
+
Logger.info( 'Network discovery thread started.' ) unless @options.arpcache
|
139
108
|
|
140
109
|
while @discovery_running
|
141
110
|
empty_list = false
|
142
111
|
|
143
|
-
if @targets.empty? and
|
112
|
+
if @targets.empty? and @options.should_discover_hosts?
|
144
113
|
empty_list = true
|
145
114
|
Logger.info 'Searching for alive targets ...'
|
146
115
|
else
|
@@ -155,7 +124,7 @@ class Context
|
|
155
124
|
|
156
125
|
@targets = Network.get_alive_targets self
|
157
126
|
|
158
|
-
if empty_list and
|
127
|
+
if empty_list and @options.should_discover_hosts?
|
159
128
|
Logger.info "Collected #{@targets.size} total targets."
|
160
129
|
@targets.each do |target|
|
161
130
|
Logger.info " #{target}"
|
@@ -169,7 +138,7 @@ class Context
|
|
169
138
|
@discovery_running = false
|
170
139
|
|
171
140
|
if @discovery_thread != nil
|
172
|
-
Logger.info( 'Stopping network discovery thread ...' ) unless @options
|
141
|
+
Logger.info( 'Stopping network discovery thread ...' ) unless @options.arpcache
|
173
142
|
|
174
143
|
begin
|
175
144
|
@discovery_thread.exit
|
@@ -179,44 +148,11 @@ class Context
|
|
179
148
|
end
|
180
149
|
|
181
150
|
def enable_port_redirection
|
182
|
-
@redirections =
|
183
|
-
|
184
|
-
if @options[:proxy]
|
185
|
-
@redirections << Redirection.new( @options[:iface],
|
186
|
-
'TCP',
|
187
|
-
80,
|
188
|
-
@ifconfig[:ip_saddr],
|
189
|
-
@options[:proxy_port] )
|
190
|
-
end
|
191
|
-
|
192
|
-
if @options[:proxy_https]
|
193
|
-
@redirections << Redirection.new( @options[:iface],
|
194
|
-
'TCP',
|
195
|
-
443,
|
196
|
-
@ifconfig[:ip_saddr],
|
197
|
-
@options[:proxy_https_port] )
|
198
|
-
end
|
199
|
-
|
200
|
-
if @options[:custom_proxy]
|
201
|
-
@redirections << Redirection.new( @options[:iface],
|
202
|
-
'TCP',
|
203
|
-
80,
|
204
|
-
@options[:custom_proxy],
|
205
|
-
@options[:custom_proxy_port] )
|
206
|
-
end
|
207
|
-
|
208
|
-
if @options[:custom_https_proxy]
|
209
|
-
@redirections << Redirection.new( @options[:iface],
|
210
|
-
'TCP',
|
211
|
-
443,
|
212
|
-
@options[:custom_https_proxy],
|
213
|
-
@options[:custom_https_proxy_port] )
|
214
|
-
end
|
215
|
-
|
151
|
+
@redirections = @options.to_redirections @ifconfig
|
216
152
|
@redirections.each do |r|
|
217
153
|
Logger.warn "Redirecting #{r.protocol} traffic from port #{r.src_port} to #{r.dst_address}:#{r.dst_port}"
|
218
154
|
|
219
|
-
@firewall.add_port_redirection( r.interface, r.protocol, r.src_port, r.dst_address, r.dst_port )
|
155
|
+
@firewall.add_port_redirection( r.interface, r.protocol, r.src_port, r.dst_address, r.dst_port )
|
220
156
|
end
|
221
157
|
end
|
222
158
|
|
@@ -224,19 +160,19 @@ class Context
|
|
224
160
|
@redirections.each do |r|
|
225
161
|
Logger.debug "Removing #{r.protocol} port redirect from port #{r.src_port} to #{r.dst_address}:#{r.dst_port}"
|
226
162
|
|
227
|
-
@firewall.del_port_redirection( r.interface, r.protocol, r.src_port, r.dst_address, r.dst_port )
|
163
|
+
@firewall.del_port_redirection( r.interface, r.protocol, r.src_port, r.dst_address, r.dst_port )
|
228
164
|
end
|
229
165
|
|
230
166
|
@redirections = []
|
231
167
|
end
|
232
168
|
|
233
169
|
def create_proxies
|
234
|
-
if
|
235
|
-
require @options
|
170
|
+
if @options.has_proxy_module?
|
171
|
+
require @options.proxy_module
|
236
172
|
|
237
173
|
Proxy::Module.register_modules
|
238
174
|
|
239
|
-
raise BetterCap::Error, "#{@options
|
175
|
+
raise BetterCap::Error, "#{@options.proxy_module} is not a valid bettercap proxy module." unless !Proxy::Module.modules.empty?
|
240
176
|
end
|
241
177
|
|
242
178
|
@proxy_processor = Proc.new do |request,response|
|
@@ -262,44 +198,42 @@ class Context
|
|
262
198
|
end
|
263
199
|
|
264
200
|
# create HTTP proxy
|
265
|
-
@
|
266
|
-
@proxy.start
|
267
|
-
|
201
|
+
@proxies << Proxy::Proxy.new( @ifconfig[:ip_saddr], @options.proxy_port, false, @proxy_processor )
|
268
202
|
# create HTTPS proxy
|
269
|
-
if @options
|
203
|
+
if @options.proxy_https
|
270
204
|
# We're not acting as a normal HTTPS proxy, thus we're not
|
271
205
|
# able to handle CONNECT requests, thus we don't know the
|
272
206
|
# hostname the client is going to connect to.
|
273
207
|
# We can only use a self signed certificate.
|
274
|
-
if @options
|
208
|
+
if @options.proxy_pem_file.nil?
|
275
209
|
@certificate = Proxy::CertStore.get_selfsigned
|
276
210
|
else
|
277
|
-
@certificate = Proxy::CertStore.from_file @options
|
211
|
+
@certificate = Proxy::CertStore.from_file @options.proxy_pem_file
|
278
212
|
end
|
279
213
|
|
280
|
-
@
|
281
|
-
|
214
|
+
@proxies << Proxy::Proxy.new( @ifconfig[:ip_saddr], @options.proxy_https_port, true, @proxy_processor )
|
215
|
+
end
|
216
|
+
|
217
|
+
@proxies.each do |proxy|
|
218
|
+
proxy.start
|
282
219
|
end
|
283
220
|
end
|
284
221
|
|
285
222
|
def finalize
|
286
223
|
stop_discovery_thread
|
287
224
|
|
288
|
-
if !@spoofer.nil? and @spoofer.length != 0
|
225
|
+
if !@spoofer.nil? and @spoofer.length != 0
|
289
226
|
@spoofer.each do |itr|
|
290
227
|
itr.stop
|
291
228
|
end
|
292
229
|
end
|
293
230
|
|
294
|
-
|
295
|
-
|
296
|
-
if !@https_proxy.nil?
|
297
|
-
@https_proxy.stop
|
298
|
-
end
|
231
|
+
@proxies.each do |proxy|
|
232
|
+
proxy.stop
|
299
233
|
end
|
300
|
-
|
234
|
+
|
301
235
|
disable_port_redirection
|
302
|
-
|
236
|
+
|
303
237
|
if !@firewall.nil?
|
304
238
|
@firewall.restore
|
305
239
|
end
|