xettercap 1.5.7xerob

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. data/bin/xettercap +61 -0
  3. data/lib/bettercap/banner +2 -0
  4. data/lib/bettercap/context.rb +259 -0
  5. data/lib/bettercap/discovery/agents/arp.rb +37 -0
  6. data/lib/bettercap/discovery/agents/base.rb +73 -0
  7. data/lib/bettercap/discovery/agents/icmp.rb +44 -0
  8. data/lib/bettercap/discovery/agents/udp.rb +30 -0
  9. data/lib/bettercap/discovery/thread.rb +128 -0
  10. data/lib/bettercap/error.rb +16 -0
  11. data/lib/bettercap/firewalls/base.rb +103 -0
  12. data/lib/bettercap/firewalls/bsd.rb +74 -0
  13. data/lib/bettercap/firewalls/linux.rb +65 -0
  14. data/lib/bettercap/firewalls/redirection.rb +42 -0
  15. data/lib/bettercap/loader.rb +27 -0
  16. data/lib/bettercap/logger.rb +131 -0
  17. data/lib/bettercap/memory.rb +56 -0
  18. data/lib/bettercap/monkey/celluloid/actor.rb +23 -0
  19. data/lib/bettercap/monkey/celluloid/io/udp_socket.rb +26 -0
  20. data/lib/bettercap/monkey/em-proxy/proxy.rb +23 -0
  21. data/lib/bettercap/monkey/openssl/server.rb +35 -0
  22. data/lib/bettercap/monkey/packetfu/pcap.rb +51 -0
  23. data/lib/bettercap/monkey/packetfu/utils.rb +210 -0
  24. data/lib/bettercap/monkey/system.rb +25 -0
  25. data/lib/bettercap/network/arp_reader.rb +91 -0
  26. data/lib/bettercap/network/hw-prefixes +21326 -0
  27. data/lib/bettercap/network/network.rb +102 -0
  28. data/lib/bettercap/network/packet_queue.rb +129 -0
  29. data/lib/bettercap/network/protos/base.rb +154 -0
  30. data/lib/bettercap/network/protos/dhcp.rb +227 -0
  31. data/lib/bettercap/network/protos/mysql.rb +40 -0
  32. data/lib/bettercap/network/protos/ntlm.rb +97 -0
  33. data/lib/bettercap/network/protos/snmp.rb +49 -0
  34. data/lib/bettercap/network/protos/teamviewer.rb +119 -0
  35. data/lib/bettercap/network/servers/dnsd.rb +152 -0
  36. data/lib/bettercap/network/servers/httpd.rb +55 -0
  37. data/lib/bettercap/network/services +2182 -0
  38. data/lib/bettercap/network/target.rb +168 -0
  39. data/lib/bettercap/network/validator.rb +96 -0
  40. data/lib/bettercap/options/core_options.rb +197 -0
  41. data/lib/bettercap/options/options.rb +165 -0
  42. data/lib/bettercap/options/proxy_options.rb +314 -0
  43. data/lib/bettercap/options/server_options.rb +73 -0
  44. data/lib/bettercap/options/sniff_options.rb +90 -0
  45. data/lib/bettercap/options/spoof_options.rb +71 -0
  46. data/lib/bettercap/pluggable.rb +37 -0
  47. data/lib/bettercap/proxy/http/module.rb +105 -0
  48. data/lib/bettercap/proxy/http/modules/injectcss.rb +79 -0
  49. data/lib/bettercap/proxy/http/modules/injecthtml.rb +80 -0
  50. data/lib/bettercap/proxy/http/modules/injectjs.rb +79 -0
  51. data/lib/bettercap/proxy/http/proxy.rb +184 -0
  52. data/lib/bettercap/proxy/http/request.rb +192 -0
  53. data/lib/bettercap/proxy/http/response.rb +226 -0
  54. data/lib/bettercap/proxy/http/ssl/authority.rb +182 -0
  55. data/lib/bettercap/proxy/http/ssl/bettercap-ca.pem +49 -0
  56. data/lib/bettercap/proxy/http/ssl/server.rb +63 -0
  57. data/lib/bettercap/proxy/http/sslstrip/cookiemonitor.rb +67 -0
  58. data/lib/bettercap/proxy/http/sslstrip/lock.ico +0 -0
  59. data/lib/bettercap/proxy/http/sslstrip/strip.rb +325 -0
  60. data/lib/bettercap/proxy/http/streamer.rb +225 -0
  61. data/lib/bettercap/proxy/stream_logger.rb +181 -0
  62. data/lib/bettercap/proxy/tcp/module.rb +75 -0
  63. data/lib/bettercap/proxy/tcp/proxy.rb +123 -0
  64. data/lib/bettercap/proxy/thread_pool.rb +194 -0
  65. data/lib/bettercap/shell.rb +70 -0
  66. data/lib/bettercap/sniffer/parsers/base.rb +87 -0
  67. data/lib/bettercap/sniffer/parsers/cookie.rb +45 -0
  68. data/lib/bettercap/sniffer/parsers/creditcard.rb +62 -0
  69. data/lib/bettercap/sniffer/parsers/custom.rb +26 -0
  70. data/lib/bettercap/sniffer/parsers/dhcp.rb +45 -0
  71. data/lib/bettercap/sniffer/parsers/dict.rb +37 -0
  72. data/lib/bettercap/sniffer/parsers/ftp.rb +24 -0
  73. data/lib/bettercap/sniffer/parsers/httpauth.rb +44 -0
  74. data/lib/bettercap/sniffer/parsers/https.rb +42 -0
  75. data/lib/bettercap/sniffer/parsers/irc.rb +24 -0
  76. data/lib/bettercap/sniffer/parsers/mail.rb +24 -0
  77. data/lib/bettercap/sniffer/parsers/mpd.rb +36 -0
  78. data/lib/bettercap/sniffer/parsers/mysql.rb +27 -0
  79. data/lib/bettercap/sniffer/parsers/nntp.rb +24 -0
  80. data/lib/bettercap/sniffer/parsers/ntlmss.rb +34 -0
  81. data/lib/bettercap/sniffer/parsers/pgsql.rb +36 -0
  82. data/lib/bettercap/sniffer/parsers/post.rb +33 -0
  83. data/lib/bettercap/sniffer/parsers/redis.rb +39 -0
  84. data/lib/bettercap/sniffer/parsers/rlogin.rb +45 -0
  85. data/lib/bettercap/sniffer/parsers/snmp.rb +44 -0
  86. data/lib/bettercap/sniffer/parsers/snpp.rb +37 -0
  87. data/lib/bettercap/sniffer/parsers/teamviewer.rb +30 -0
  88. data/lib/bettercap/sniffer/parsers/url.rb +30 -0
  89. data/lib/bettercap/sniffer/parsers/whatsapp.rb +33 -0
  90. data/lib/bettercap/sniffer/sniffer.rb +142 -0
  91. data/lib/bettercap/spoofers/arp.rb +150 -0
  92. data/lib/bettercap/spoofers/base.rb +152 -0
  93. data/lib/bettercap/spoofers/icmp.rb +202 -0
  94. data/lib/bettercap/spoofers/none.rb +57 -0
  95. data/lib/bettercap/update_checker.rb +57 -0
  96. data/lib/bettercap/version.rb +18 -0
  97. data/lib/bettercap.rb +70 -0
  98. metadata +276 -0
@@ -0,0 +1,226 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+
4
+ BETTERCAP
5
+
6
+ Author : Simone 'evilsocket' Margaritelli
7
+ Email : evilsocket@gmail.com
8
+ Blog : http://www.evilsocket.net/
9
+
10
+ This project is released under the GPL 3 license.
11
+
12
+ =end
13
+
14
+ module BetterCap
15
+ module Proxy
16
+ module HTTP
17
+
18
+ # HTTP response parser.
19
+ class Response
20
+ # HTTP protocol version
21
+ attr_accessor :version
22
+ # Response status code.
23
+ attr_accessor :code
24
+ # Response status message
25
+ attr_accessor :status
26
+ # Response content type.
27
+ attr_reader :content_type
28
+ # Response charset, default to UTF-8.
29
+ attr_reader :charset
30
+ # Response content length.
31
+ attr_reader :content_length
32
+ # True if this is a chunked encoded response, otherwise false.
33
+ attr_reader :chunked
34
+ # A list of response headers.
35
+ attr_accessor :headers
36
+ # Response body.
37
+ attr_accessor :body
38
+
39
+ # Return a 200 response object reading the file +filename+ with the specified
40
+ # +content_type+.
41
+ def self.from_file( filename, content_type )
42
+ r = Response.new
43
+ data = File.read(filename)
44
+
45
+ r << "HTTP/1.1 200 OK"
46
+ r << "Connection: close"
47
+ r << "Content-Length: #{data.bytesize}"
48
+ r << "Content-Type: #{content_type}"
49
+ r << "\n"
50
+ r << data
51
+
52
+ r
53
+ end
54
+
55
+ # Return a 302 response object redirecting to +url+, setting optional +cookies+.
56
+ def self.redirect( url, cookies = [] )
57
+ r = Response.new
58
+
59
+ r << "HTTP/1.1 302 Moved"
60
+ r << "Location: #{url}"
61
+
62
+ cookies.each do |cookie|
63
+ r << "Set-Cookie: #{cookie}"
64
+ end
65
+
66
+ r << "Connection: close"
67
+ r << "\n\n"
68
+
69
+ r
70
+ end
71
+
72
+ # Initialize this response object state.
73
+ def initialize
74
+ @version = '1.1'
75
+ @code = 200
76
+ @status = 'OK'
77
+ @content_type = nil
78
+ @charset = 'UTF-8'
79
+ @content_length = nil
80
+ @body = nil
81
+ @headers = {}
82
+ @headers_done = false
83
+ @chunked = false
84
+ end
85
+
86
+ # Convert a webrick response to this class.
87
+ def convert_webrick_response!(response)
88
+ self << "HTTP/#{response.http_version} #{response.code} #{response.msg}"
89
+ response.each do |key,value|
90
+ # sometimes webrick joins all 'set-cookie' headers
91
+ # which might cause issues with HSTS bypass.
92
+ if key == 'set-cookie'
93
+ response.get_fields('set-cookie').each do |v|
94
+ self << "Set-Cookie: #{v}"
95
+ end
96
+ else
97
+ self << "#{key.gsub(/\bwww|^te$|\b\w/){ $&.upcase }}: #{value}"
98
+ end
99
+ end
100
+ self << "\n"
101
+ @code = response.code
102
+ @body = response.body || ''
103
+ end
104
+
105
+ # Parse a single response +line+.
106
+ def <<(line)
107
+ # we already parsed the heders, collect response body
108
+ if @headers_done
109
+ @body = '' if @body.nil?
110
+ @body << line.force_encoding( @charset )
111
+ else
112
+ chomped = line.chomp
113
+ Logger.debug " RESPONSE LINE: '#{chomped}'"
114
+
115
+ # is this the first line 'HTTP/<VERSION> <CODE> <STATUS>' ?
116
+ if chomped =~ /^HTTP\/([\d\.]+)\s+(\d+)\s+(.+)$/
117
+ @version = $1
118
+ @code = $2.to_i
119
+ @status = $3
120
+
121
+ # collect and fix headers
122
+ elsif chomped =~ /^([^:\s]+)\s*:\s*(.+)$/i
123
+ name = $1
124
+ value = $2
125
+
126
+ if name == 'Content-Type'
127
+ @content_type = value
128
+ if value =~ /^(.+);\s*charset=(.+)/i
129
+ @content_type = $1
130
+ @charset = $2.chomp
131
+ end
132
+ elsif name == 'Content-Length'
133
+ @content_length = value.to_i
134
+ # check if we have a chunked encoding
135
+ elsif name == 'Transfer-Encoding' and value == 'chunked'
136
+ @chunked = true
137
+ name = nil
138
+ value = nil
139
+ end
140
+
141
+ unless name.nil? or value.nil?
142
+ if @headers.has_key?(name)
143
+ if @headers[name].is_a?(Array)
144
+ @headers[name] << value
145
+ else
146
+ @headers[name] = [ @headers[name], value ]
147
+ end
148
+ else
149
+ @headers[name] = value
150
+ end
151
+ end
152
+ # last line, we're done with the headers
153
+ elsif chomped.empty?
154
+ @headers_done = true
155
+ end
156
+ end
157
+ end
158
+
159
+ # Return true if the response content type is textual, otherwise false.
160
+ def textual?
161
+ @content_type and ( @content_type =~ /^text\/.+/ or @content_type =~ /^application\/.+/ )
162
+ end
163
+
164
+ # Return the value of header with +name+ or an empty string.
165
+ def [](name)
166
+ ( @headers.has_key?(name) ? @headers[name] : "" )
167
+ end
168
+
169
+ # If the header with +name+ is found, then a +value+ is assigned to it,
170
+ # otherwise it's created.
171
+ def []=(name, value)
172
+ if @headers.has_key?(name)
173
+ if value.nil?
174
+ @headers.delete(name)
175
+ else
176
+ @headers[name] = value
177
+ end
178
+ elsif !value.nil?
179
+ @headers[name] = value
180
+ end
181
+ end
182
+
183
+ # Search for header +name+ and apply a gsub substitution:
184
+ # value.gsub( +search+, +replace+ )
185
+ def patch_header!( name, search, replace )
186
+ value = self[name]
187
+ unless value.empty?
188
+ patched = []
189
+ if value.is_a?(Array)
190
+ value.each do |v|
191
+ patched << v.gsub( search, replace )
192
+ end
193
+ else
194
+ patched << value.gsub( search, replace )
195
+ end
196
+
197
+ self[name] = patched
198
+ end
199
+ end
200
+
201
+ # Return a string representation of this response object, patching the
202
+ # Content-Length header if the #body was modified.
203
+ def to_s
204
+ # update content length in case the body was modified.
205
+ if @headers.has_key?('Content-Length')
206
+ @headers['Content-Length'] = @body.nil?? 0 : @body.bytesize
207
+ end
208
+
209
+ s = "HTTP/#{@version} #{@code} #{@status}\n"
210
+ @headers.each do |name,value|
211
+ if value.is_a?(Array)
212
+ value.each do |v|
213
+ s << "#{name}: #{v}\n"
214
+ end
215
+ else
216
+ s << "#{name}: #{value}\n"
217
+ end
218
+ end
219
+ s << "\n" + ( @body.nil?? "\n" : @body )
220
+ s
221
+ end
222
+ end
223
+
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,182 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+
4
+ BETTERCAP
5
+
6
+ Author : Simone 'evilsocket' Margaritelli
7
+ Email : evilsocket@gmail.com
8
+ Blog : http://www.evilsocket.net/
9
+
10
+ This project is released under the GPL 3 license.
11
+
12
+ =end
13
+
14
+ module BetterCap
15
+ module Proxy
16
+ module HTTP
17
+ module SSL
18
+
19
+ # Simple wrapper class used to fetch a server HTTPS certificate.
20
+ class Fetcher < Net::HTTP
21
+ # The server HTTPS certificate.
22
+ attr_accessor :certificate
23
+ # Overridden from Net::HTTP in order to save the peer certificate
24
+ # before the connection is closed.
25
+ def on_connect
26
+ @certificate = peer_cert
27
+ end
28
+ # Fetch the HTTPS certificate of +hostname+:+port+.
29
+ def self.fetch( hostname, port )
30
+ http = self.new( hostname, port )
31
+ http.use_ssl = true
32
+ http.ssl_timeout =
33
+ http.open_timeout =
34
+ http.read_timeout = 10
35
+
36
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
37
+
38
+ http.head("/")
39
+ http.certificate
40
+ end
41
+ end
42
+
43
+ # Used as an on-disk cache of server certificates.
44
+ class Store
45
+ # The store path.
46
+ PATH = File.join( Dir.home, '.bettercap', 'certificates' )
47
+
48
+ # Create an instance of this class.
49
+ def initialize
50
+ unless File.directory?( Store::PATH )
51
+ Logger.info "[#{'SSL'.green}] Initializing certificates store '#{Store::PATH}' ..."
52
+ FileUtils.mkdir_p( Store::PATH )
53
+ end
54
+
55
+ @store = {}
56
+ @lock = Mutex.new
57
+ end
58
+
59
+ # Find the +hostname+:+port+ certificate and return it.
60
+ def find( hostname, port )
61
+ key = Digest::SHA256.hexdigest( "#{hostname}_#{port}" )
62
+
63
+ @lock.synchronize {
64
+ unless @store.has_key?(key)
65
+ # Certificate not available in memory, search it in the store PATH.
66
+ filename = File.join( Store::PATH, key )
67
+ s_cert = load_from_file( filename )
68
+ # Not available on disk too, fetch it from the server and save it.
69
+ if s_cert.nil?
70
+ Logger.info "[#{'SSL'.green}] Fetching certificate from #{hostname}:#{port} ..."
71
+
72
+ s_cert = Fetcher.fetch( hostname, port )
73
+ save_to_file( s_cert, filename )
74
+ else
75
+ Logger.debug "[#{'SSL'.green}] Loaded HTTPS certificate for '#{hostname}' from store."
76
+ end
77
+
78
+ @store[key] = s_cert
79
+ end
80
+ }
81
+
82
+ @store[key]
83
+ end
84
+
85
+ private
86
+
87
+ # Load and return a certificate from +filename+ if it exists, also check if
88
+ # the certificate is expired, in which case it will remove it and return nil.
89
+ def load_from_file( filename )
90
+ cert = nil
91
+ if File.exist?(filename)
92
+ data = File.read(filename)
93
+ cert = OpenSSL::X509::Certificate.new(data)
94
+ # Check if expired.
95
+ now = Time.now
96
+ if now < cert.not_before or now > cert.not_after
97
+ File.delete( filename )
98
+ cert = nil
99
+ end
100
+ end
101
+ cert
102
+ end
103
+
104
+ # Save the +cert+ certificate to +filename+ encoded as PEM.
105
+ def save_to_file( cert, filename )
106
+ File.open( filename, "w+" ) { |file| file.write(cert.to_pem) }
107
+ end
108
+ end
109
+
110
+ # This class represents bettercap's HTTPS CA.
111
+ class Authority
112
+ # Default CA file.
113
+ DEFAULT = File.join( Dir.home, '.bettercap', 'bettercap-ca.pem' )
114
+
115
+ # CA certificate.
116
+ attr_reader :certificate
117
+ # CA key.
118
+ attr_reader :key
119
+
120
+ # Create an instance of this class loading the certificate and key from
121
+ # +filename+ which is expected to be a PEM formatted file.
122
+ # If +filename+ is nil, Authority::DEFAULT will be used instead.
123
+ def initialize( filename = nil )
124
+ install_ca
125
+ filename ||= Authority::DEFAULT
126
+
127
+ Logger.info "[#{'SSL'.green}] Loading HTTPS Certification Authority from '#{filename}' ..."
128
+
129
+ begin
130
+ pem = File.read(filename)
131
+
132
+ @certificate = OpenSSL::X509::Certificate.new(pem)
133
+ @key = OpenSSL::PKey::RSA.new(pem)
134
+ @store = Store.new
135
+ @cache = {}
136
+ @lock = Mutex.new
137
+ rescue Errno::ENOENT
138
+ raise BetterCap::Error, "'#{filename}' - No such file or directory."
139
+
140
+ rescue OpenSSL::X509::CertificateError
141
+ raise BetterCap::Error, "'#{filename}' - Missing or invalid certificate."
142
+
143
+ rescue OpenSSL::PKey::RSAError
144
+ raise BetterCap::Error, "'#{filename}' - Missing or invalid key."
145
+ end
146
+ end
147
+
148
+ # Fetch the certificate from +hostname+:+port+, sign it with our own CA and
149
+ # return it.
150
+ def spoof( hostname, port = 443 )
151
+ @lock.synchronize {
152
+ unless @cache.has_key?(hostname)
153
+ # 1. fetch real server certificate
154
+ s_cert = @store.find( hostname, port )
155
+ # 2. Sign it with our CA.
156
+ s_cert.public_key = @key.public_key
157
+ s_cert.issuer = @certificate.subject
158
+ s_cert.sign( @key, OpenSSL::Digest::SHA256.new )
159
+ # 3. Profit ^_^
160
+ @cache[hostname] = s_cert
161
+ end
162
+ }
163
+ @cache[hostname]
164
+ end
165
+
166
+ def install_ca
167
+ unless File.exist?( Authority::DEFAULT )
168
+ root = File.join( Dir.home, '.bettercap' )
169
+ source = File.dirname(__FILE__) + '/bettercap-ca.pem'
170
+
171
+ Logger.info "[#{'SSL'.green}] Installing CA to #{root} ..."
172
+
173
+ FileUtils.mkdir_p( root )
174
+ FileUtils.cp( source, root )
175
+ end
176
+ end
177
+ end
178
+
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,49 @@
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCaoeZj2x7hY4RV
3
+ L4S6F6GfsEAye1/rTivXQCBsEMdBifPFCWz4i1s5v1CbxO4x4dfgtJiVniGyMsnQ
4
+ pWOsZ/kjt74FIzgA2A7RTsz6+jvxFnw8uNH2UvHAlXerpghBw7F46HTKb7fPGlXI
5
+ eMrXd7SQ9fonNM1fQ0L37+ILAaZIIXjm3bM7KWuM7+8qr2bxLxP9A1ud5ruOLNF+
6
+ jxcCykm6ir/eo3M+4Yo9pOwsIvg9foOw7ahEVSB7nAZB9J2ohbCFfG7sFhKKgWFT
7
+ xKBiEHny8qaD1/16FID/SZVXhFjjK2n8Gd87cIk104392H/MQVWui9rkocwszCov
8
+ jFVOnlhjAgMBAAECggEAAM/Ivc1wpA45q5jMQY3OM2BhdeJf5oRKhp63jNmpshZf
9
+ STF7ePKCUBNJAQhPl8NvtqY8Bs0FsEHD/Wxg0Y7aJ+3W+X/t01NPAJpBSS/3EJTl
10
+ ogv2TiyxSCmAr033zSCR1eiidE2R0Wx59strhSYDtJ8V6Q7F5TIdL9/6d8RScx53
11
+ xT/efogV3ebmXNhOOG6FrjQ5uCW7KZUXRaL3nozhEldFpzjak1XKVgKLv7OBaLwI
12
+ tCgVGkfJpZbTYV2sht32JAwkEyTPtS8/49A4RRu5c62pLiDK5TkQGxtBLBpBTFoi
13
+ f95LeqyApRDR5zTeP8uvHyK/Of5YBLJljkx+YDYugQKBgQDJN4KXOhV4DGVvriwA
14
+ RBEd5nNJ/t/MATcGrFX4uqApdsMux9cpRaNa1hRxn2icm/whHrOFaBROAB7L6Zd4
15
+ uLnrzpwFTq9YMH4AXe+sPphAtuk7ZULj1qkZ3yOjiKAJcJ4LWUxQ3H32KU6GIu+e
16
+ x/e+B95pmk+s9XKajMSkKaMkWwKBgQDEu4fzhRyVvntq1s6D5R9du9eRV/6E5hLs
17
+ gylMx8smzHQ46Ef5df5uEJUfkzyCJmOMGpKAW5czsLgKkx05Xw97xwn++/9lhHas
18
+ E4SFArrIkAvBmiM44fZSKY3sVUWAHKYJy+Lg/7SR4cFVOxRyYhrFLjeXb9mOEdTo
19
+ a6xmM3M6mQKBgDRpqDOaJqN5nyaDGOUM1eSS9a7tm//4xQuQ8mfyvOtwCxFxbqNK
20
+ h22O3A5otogsvXUnGR4D6V4T+/GjrBf/DjbVP6DGSThQkVGpJlgYifI5cvFMxCqy
21
+ 7KNXk2HyobUzx4cvQIjDlm/7fH/GM+KJNggi5pVdY6mq2apWRpZ4Xg2HAoGBAJOs
22
+ WQ6Yuq5Ev4uhFn+2+2Z23AeDz8+ejFHw2o2B46KKEiutYGmHAqdH10hOUzs26b5/
23
+ K70iA0uPuXZmm6c3Df5Rl9VI/5sKZbIhLHZTaDWouspmk03df/KIsrnWAEd8Ob5c
24
+ xz8xci+XEHKT2HNL5OBiIuSP1vRnujOEr3I/6JzxAoGBAJlu4gjm8StuL5ALy43a
25
+ K62Nrsio/RhPjVUKXMtzTOgf2f2mRn04YibRNbB5Gzum4oWkjyue7qhBjIt/FX1Z
26
+ kecFhr5JG4u/yyR6R2BMw4Jvh9kV6Y/GnDpSga8sK2P3QKFD01Qtw72x5xCj94CL
27
+ kWqGcTRdiMAWQsRKvndzWAMc
28
+ -----END PRIVATE KEY-----
29
+ -----BEGIN CERTIFICATE-----
30
+ MIIDZzCCAk+gAwIBAgIJANKD84I3l13QMA0GCSqGSIb3DQEBCwUAMEoxCzAJBgNV
31
+ BAYTAlVTMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYDVQQKDAliZXR0ZXJjYXAx
32
+ EjAQBgNVBAMMCWJldHRlcmNhcDAeFw0xNjAyMjMwMTAxNTlaFw0xNzAyMjIwMTAx
33
+ NTlaMEoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYDVQQK
34
+ DAliZXR0ZXJjYXAxEjAQBgNVBAMMCWJldHRlcmNhcDCCASIwDQYJKoZIhvcNAQEB
35
+ BQADggEPADCCAQoCggEBAJqh5mPbHuFjhFUvhLoXoZ+wQDJ7X+tOK9dAIGwQx0GJ
36
+ 88UJbPiLWzm/UJvE7jHh1+C0mJWeIbIyydClY6xn+SO3vgUjOADYDtFOzPr6O/EW
37
+ fDy40fZS8cCVd6umCEHDsXjodMpvt88aVch4ytd3tJD1+ic0zV9DQvfv4gsBpkgh
38
+ eObdszspa4zv7yqvZvEvE/0DW53mu44s0X6PFwLKSbqKv96jcz7hij2k7Cwi+D1+
39
+ g7DtqERVIHucBkH0naiFsIV8buwWEoqBYVPEoGIQefLypoPX/XoUgP9JlVeEWOMr
40
+ afwZ3ztwiTXTjf3Yf8xBVa6L2uShzCzMKi+MVU6eWGMCAwEAAaNQME4wHQYDVR0O
41
+ BBYEFBspFbBsNWr57dZicWMDjOaRxQoPMB8GA1UdIwQYMBaAFBspFbBsNWr57dZi
42
+ cWMDjOaRxQoPMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJXGBH8H
43
+ DKttB8KIbFzVRVcBQ5Wvw+3oFVlmnotQuxz17fGr2ZXEPiY8/P89MgAUqVkiaIS5
44
+ EZOnIfPu7icGWvT0N3eoxnLaTdCFy0NOHXJh2+zrav5FWsULsmSxOBxItvkxq0fN
45
+ yk1P/5kLmrJKnKUJKH7QDjNeEqJdfSx+dg2435a5pcvrVfjCGrd8F8CIED6sYd0n
46
+ pibpJXi8TILiPrjNhTWT2Y5XflfV3Ho/+jIbeY3wzsApwsBINy0ticABdPhtEGHk
47
+ nkR6dqDv1rSuzify5OdYeLy/UX4R/vv1BS0PLScE1lUB16ybzJ2imWJgOQs6J4E6
48
+ hHakJaVPVAPFWUU=
49
+ -----END CERTIFICATE-----
@@ -0,0 +1,63 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+
4
+ BETTERCAP
5
+
6
+ Author : Simone 'evilsocket' Margaritelli
7
+ Email : evilsocket@gmail.com
8
+ Blog : http://www.evilsocket.net/
9
+
10
+ This project is released under the GPL 3 license.
11
+
12
+ =end
13
+
14
+ module BetterCap
15
+ module Proxy
16
+ module HTTP
17
+ module SSL
18
+
19
+ # Little utility class to handle SSLServer creation.
20
+ class Server
21
+ # The SSL certification authority.
22
+ attr_reader :authority
23
+ # Main SSLContext instance.
24
+ attr_reader :context
25
+ # Socket I/O object.
26
+ attr_reader :io
27
+
28
+ # Create an instance from the TCPSocket +socket+.
29
+ def initialize( socket )
30
+ @authority = Authority.new( Context.get.options.proxies.proxy_pem_file )
31
+ @context = OpenSSL::SSL::SSLContext.new
32
+ @context.cert = @authority.certificate
33
+ @context.key = @authority.key
34
+
35
+ # If the client supports SNI ( https://en.wikipedia.org/wiki/Server_Name_Indication )
36
+ # we'll receive the hostname it wants to connect to in this callback.
37
+ # Use the CA we already have loaded ( or generated ) to sign a new
38
+ # certificate at runtime with the correct 'Common Name' and create a new SSL
39
+ # context with it, these are the steps:
40
+ #
41
+ # 1. Get hostname from SNI.
42
+ # 2. Fetch upstream certificate from the real server.
43
+ # 3. Resign it with our own CA.
44
+ # 4. Create a new context with the new spoofed certificate.
45
+ # 5. Profit ^_^
46
+ @context.servername_cb = proc { |sslsocket, hostname|
47
+ Logger.debug "[#{'SSL'.green}] Server-Name-Indication for '#{hostname}'"
48
+
49
+ ctx = OpenSSL::SSL::SSLContext.new
50
+ ctx.cert = @authority.spoof( hostname )
51
+ ctx.key = @authority.key
52
+
53
+ ctx
54
+ }
55
+
56
+ @io = OpenSSL::SSL::SSLServer.new( socket, @context )
57
+ end
58
+ end
59
+
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+
4
+ BETTERCAP
5
+
6
+ Author : Simone 'evilsocket' Margaritelli
7
+ Email : evilsocket@gmail.com
8
+ Blog : http://www.evilsocket.net/
9
+
10
+ This project is released under the GPL 3 license.
11
+
12
+ =end
13
+
14
+ module BetterCap
15
+ module Proxy
16
+ module HTTP
17
+ module SSLStrip
18
+
19
+ # Class to handle a cookies for sslstrip.
20
+ class CookieMonitor
21
+ # Create an instance of this object.
22
+ def initialize
23
+ @set = []
24
+ end
25
+
26
+ def add!(request)
27
+ @set << [request.client, get_domain(request)]
28
+ end
29
+
30
+ # Return true if the +request+ was already cleaned.
31
+ def is_clean?(request)
32
+ if request.post?
33
+ return true
34
+ elsif request['Cookie'].empty?
35
+ return true
36
+ else
37
+ return @set.include?( [request.client, get_domain(request)] )
38
+ end
39
+ end
40
+
41
+ # Build cookie expiration headers for the +request+ and add its domain
42
+ # to our list.
43
+ def get_expired_headers!(request)
44
+ domain = get_domain(request)
45
+ @set << [request.client, domain]
46
+
47
+ expired = []
48
+ request['Cookie'].split(';').each do |cookie|
49
+ cname = cookie.split("=")[0].strip
50
+ expired << "#{cname}=EXPIRED; path=/; domain=#{domain}; Expires=Mon, 01-Jan-1990 00:00:00 GMT"
51
+ expired << "#{cname}=EXPIRED; path=/; domain=#{request.host}; Expires=Mon, 01-Jan-1990 00:00:00 GMT"
52
+ end
53
+
54
+ expired
55
+ end
56
+
57
+ # Return the cookie domain given the +request+ object.
58
+ def get_domain(request)
59
+ parts = request.host.split('.')
60
+ ".#{parts[-2]}.#{parts[-1]}"
61
+ end
62
+ end
63
+
64
+ end
65
+ end
66
+ end
67
+ end