Class: Watobo::Interceptor::Proxy
- Inherits:
-
Object
- Object
- Watobo::Interceptor::Proxy
show all
- Includes:
- Constants
- Defined in:
- lib/watobo/interceptor/proxy.rb
Constant Summary
Constants included
from Constants
Constants::AC_GROUP_APACHE, Constants::AC_GROUP_DOMINO, Constants::AC_GROUP_ENUMERATION, Constants::AC_GROUP_FILE_INCLUSION, Constants::AC_GROUP_FLASH, Constants::AC_GROUP_GENERIC, Constants::AC_GROUP_JBOSS, Constants::AC_GROUP_JOOMLA, Constants::AC_GROUP_SAP, Constants::AC_GROUP_SQL, Constants::AC_GROUP_TYPO3, Constants::AC_GROUP_XSS, Constants::AUTH_TYPE_BASIC, Constants::AUTH_TYPE_DIGEST, Constants::AUTH_TYPE_NONE, Constants::AUTH_TYPE_NTLM, Constants::AUTH_TYPE_UNKNOWN, Constants::CHAT_SOURCE_AUTO_SCAN, Constants::CHAT_SOURCE_FUZZER, Constants::CHAT_SOURCE_INTERCEPT, Constants::CHAT_SOURCE_MANUAL, Constants::CHAT_SOURCE_MANUAL_SCAN, Constants::CHAT_SOURCE_PROXY, Constants::CHAT_SOURCE_UNDEF, Constants::DEFAULT_PORT_HTTP, Constants::DEFAULT_PORT_HTTPS, Constants::FINDING_TYPE_HINT, Constants::FINDING_TYPE_INFO, Constants::FINDING_TYPE_UNDEFINED, Constants::FINDING_TYPE_VULN, Constants::FIRST_TIME_FILE, Constants::GUI_REGULAR_FONT_SIZE, Constants::GUI_SMALL_FONT_SIZE, Constants::ICON_PATH, Constants::LOG_DEBUG, Constants::LOG_INFO, Constants::SCAN_CANCELED, Constants::SCAN_FINISHED, Constants::SCAN_PAUSED, Constants::SCAN_STARTED, Constants::TE_CHUNKED, Constants::TE_COMPRESS, Constants::TE_DEFLATE, Constants::TE_GZIP, Constants::TE_IDENTITY, Constants::TE_NONE, Constants::VULN_RATING_CRITICAL, Constants::VULN_RATING_HIGH, Constants::VULN_RATING_INFO, Constants::VULN_RATING_LOW, Constants::VULN_RATING_MEDIUM, Constants::VULN_RATING_UNDEFINED
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(settings = nil) ⇒ Proxy
Returns a new instance of Proxy.
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
|
# File 'lib/watobo/interceptor/proxy.rb', line 424
def initialize(settings=nil)
@event_dispatcher_listeners = Hash.new
@pass_through_hosts = ['safebrowsing.*google\.com', 'download.cdn.mozilla.net', 'shavar.services.mozilla.com']
begin
puts
puts "=== Initialize Interceptor/Proxy ==="
init_instance_vars
@srv_path = File.join(File.dirname(__FILE__), 'html')
@awaiting_requests = 0
@awaiting_responses = 0
@request_filter_settings = {
:site_in_scope => false,
:method_filter => '(get|post|put)',
:negate_method_filter => false,
:negate_url_filter => false,
:url_filter => '',
:file_type_filter => '(jpg|gif|png|jpeg|bmp)',
:negate_file_type_filter => true,
:parms_filter => '',
:negate_parms_filter => false
}
@response_filter_settings = {
:content_type_filter => '(text|script)',
:negate_content_type_filter => false,
:response_code_filter => '2\d{2}',
:negate_response_code_filter => false,
:request_intercepted => false,
:content_printable => true,
:enable_printable_check => false
}
@preview = Hash.new
@preview['ProxyTest'] = ["HTTP/1.0 200 OK\r\nServer: Watobo-Interceptor\r\nConnection: close\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n<html><body>PROXY_OK</body></html>"]
@dh_key = Watobo::CA.dh_key
rescue => bang
puts "!!!could not read certificate files:"
puts bang
puts bang.backtrace if $DEBUG
end
end
|
Instance Attribute Details
#client_certificates ⇒ Object
17
18
19
|
# File 'lib/watobo/interceptor/proxy.rb', line 17
def client_certificates
@client_certificates
end
|
#port ⇒ Object
Returns the value of attribute port.
9
10
11
|
# File 'lib/watobo/interceptor/proxy.rb', line 9
def port
@port
end
|
#proxy_mode ⇒ Object
Returns the value of attribute proxy_mode.
11
12
13
|
# File 'lib/watobo/interceptor/proxy.rb', line 11
def proxy_mode
@proxy_mode
end
|
#target ⇒ Object
attr_accessor :contentLength attr_accessor :contentTypes
15
16
17
|
# File 'lib/watobo/interceptor/proxy.rb', line 15
def target
@target
end
|
Class Method Details
.start(settings = {}) ⇒ Object
129
130
131
132
133
|
# File 'lib/watobo/interceptor/proxy.rb', line 129
def self.start(settings = {})
proxy = Proxy.new(settings)
proxy.start
proxy
end
|
Instance Method Details
#addPreview(response) ⇒ Object
105
106
107
108
109
|
# File 'lib/watobo/interceptor/proxy.rb', line 105
def addPreview(response)
preview_id = Digest::MD5.hexdigest(response.join)
@preview[preview_id] = response
return preview_id
end
|
#cert_response ⇒ Object
57
58
59
60
61
62
63
64
65
|
# File 'lib/watobo/interceptor/proxy.rb', line 57
def cert_response
crt_file = File.join(Watobo.working_directory, "CA", "cacert.pem")
= ["HTTP/1.0 200 OK", "Server: Watobo-Interceptor", "Connection: close", "Content-Type: application/x-pem-file"]
content = File.read(crt_file)
<< "Content-Length: #{content.length}"
r = .join("\r\n")
r << "\r\n\r\n"
r << content
end
|
#clear_request_carvers ⇒ Object
96
97
98
99
|
# File 'lib/watobo/interceptor/proxy.rb', line 96
def clear_request_carvers
@request_carvers.clear unless @request_carvers.nil?
end
|
#clear_response_carvers ⇒ Object
101
102
103
|
# File 'lib/watobo/interceptor/proxy.rb', line 101
def clear_response_carvers
@response_carvers.clear unless @response_carvers.nil?
end
|
#clearEvents(event) ⇒ Object
75
76
77
|
# File 'lib/watobo/interceptor/proxy.rb', line 75
def clearEvents(event)
@event_dispatcher_listener[event].clear
end
|
#getRequestFilter ⇒ Object
83
84
85
|
# File 'lib/watobo/interceptor/proxy.rb', line 83
def getRequestFilter()
YAML.load(YAML.dump(@request_filter_settings))
end
|
#getResponseFilter ⇒ Object
79
80
81
|
# File 'lib/watobo/interceptor/proxy.rb', line 79
def getResponseFilter()
YAML.load(YAML.dump(@response_filter_settings))
end
|
#refresh_www_auth ⇒ Object
420
421
422
|
# File 'lib/watobo/interceptor/proxy.rb', line 420
def refresh_www_auth
@www_auth = Watobo::Conf::Scanner.www_auth
end
|
#server ⇒ Object
67
68
69
|
# File 'lib/watobo/interceptor/proxy.rb', line 67
def server
@bind_addr
end
|
#setRequestFilter(new_settings) ⇒ Object
91
92
93
94
|
# File 'lib/watobo/interceptor/proxy.rb', line 91
def setRequestFilter(new_settings)
@request_filter_settings.update new_settings unless new_settings.nil?
end
|
#setResponseFilter(new_settings) ⇒ Object
87
88
89
|
# File 'lib/watobo/interceptor/proxy.rb', line 87
def setResponseFilter(new_settings)
@response_filter_settings.update new_settings unless new_settings.nil?
end
|
#start ⇒ Object
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
|
# File 'lib/watobo/interceptor/proxy.rb', line 135
def start()
@wait_queue = Queue.new
if transparent?
Watobo::Interceptor::Transparent.start
end
begin
@intercept_srv = TCPServer.new(@bind_addr, @port)
@intercept_srv.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1)
rescue => bang
puts "\n!!!Could not start InterceptProxy"
puts bang
return nil
end
puts "\n* Intercepor started on #{@bind_addr}:#{@port}"
session_list = []
puts "!!! TRANSPARENT MODE ENABLED !!!" if transparent?
@t_server = Thread.new(@intercept_srv) { |server|
while (new_session = server.accept)
new_sender = Watobo::Session.new(@target)
Thread.new(new_sender, new_session) { |sender, session|
c_sock = Watobo::HTTPSocket::ClientSocket.connect(session)
Thread.exit if c_sock.nil?
max_loop = 0
loop do
flags = []
begin
request = c_sock.request
if request.nil? or request.empty? then
print "c/"
c_sock.close
Thread.exit
end
url = (request.url.to_s.length > 65) ? request.url.to_s.slice(0, 65) + "..." : request.url.to_s
puts "\n[I] #{url}"
rescue => bang
puts "!!! Error reading client request "
puts bang
puts bang.backtrace
c_sock.close
Thread.exit
end
if request.host =='watobo.localhost' or request.first =~ /WATOBOPreview/ then
if request.first =~ /WATOBOPreview=([0-9a-zA-Z]*)/ then
hashid = $1
response = @preview[hashid]
if response then
c_sock.write response.join
c_sock.close
end
end
Thread.exit
end
if request.host =~ /^watobo$/
if request.path =~ /watobo\.pem/
response = cert_response
else
response = watobo_srv_get(request.path)
end
c_sock.write response
c_sock.close
Thread.exit
end
request_intercepted = false
if Watobo::Interceptor.rewrite_requests? then
Interceptor::RequestCarver.shape(request, flags)
puts "FLAGS >>"
puts flags
end
if @target and Watobo::Interceptor.intercept_requests? then
if matchRequestFilter(request)
@awaiting_requests += 1
request_intercepted = true
if @target.respond_to? :addRequest
Watobo.print_debug "send request to target"
@target.addRequest(request, Thread.current)
Thread.stop
else
p "! no target for editing request"
end
@awaiting_requests -= 1
end
end
begin
s_sock, req, resp = sender.sendHTTPRequest(request, :update_sids => true,
:update_session => false,
:update_contentlength => true,
:www_auth => @www_auth
)
if s_sock.nil? then
puts "s_sock is nil! bye, bye, ..."
puts request if $DEBUG
c_sock.write resp.join unless resp.nil?
c_sock.close
Thread.exit
end
rescue => bang
puts bang
puts bang.backtrace if $DEBUG
c_sock.close
Thread.exit
end
if isPassThrough?(req, resp, s_sock, c_sock)
Watobo::HTTPSocket.close s_sock
c_sock.close
Thread.exit
end
begin
missing_credentials = false
rs = resp.status
auth_type = AUTH_TYPE_NONE
if rs =~ /^(401|407)/ then
missing_credentials = true
resp.each do |rl|
if rl =~ /^(Proxy|WWW)-Authenticate: Basic/i
auth_type = AUTH_TYPE_BASIC
break
elsif rl =~ /^(Proxy|WWW)-Authenticate: NTLM/i
auth_type = AUTH_TYPE_NTLM
break
end
end
unless auth_type == AUTH_TYPE_NONE
if auth_type == AUTH_TYPE_NTLM
if rs =~ /^401/ then
resp.push "WATOBO: Server requires (NTLM) authorization, please set WWW_Auth Credentials!"
resp.shift
resp.unshift "HTTP/1.1 200 OK\r\n"
else
resp.push "WATOBO: Proxy requires (NTLM) authorization, please set Proxy Credentials!"
resp.shift
resp.unshift "HTTP/1.1 200 OK\r\n"
end
end
end
end
unless auth_type == AUTH_TYPE_UNKNOWN or req.method =~ /^head/i
sender.readHTTPBody(s_sock, resp, req, :update_sids => true)
Watobo::HTTPSocket.close s_sock
end
rescue => bang
puts "!!! could not send request !!!"
puts bang
puts bang.backtrace if $DEBUG
end
begin
resp.unchunk!
resp.unzip!
if Watobo::Interceptor.rewrite_responses? then
Interceptor::ResponseCarver.shape(resp, flags)
end
if @target and Watobo::Interceptor.intercept_responses? then
if matchResponseFilter(resp)
if @target.respond_to? :modifyResponse
@target.modifyResponse(resp, Thread.current)
Thread.stop
else
p "! no target for editing response"
end
end
end
if missing_credentials
resp.("Connection", "close")
elsif request.connection_close? or resp.content_length < 0 or max_loop > 4
resp.("Connection", "close")
else
resp.("Connection", "keep-alive")
resp.("Keep-Alive", "max=4, timeout=120")
end
resp_data = resp.join
c_sock.write resp_data
chat = Chat.new(request.copy, resp.copy, :source => CHAT_SOURCE_INTERCEPT)
Watobo::Chats.add chat
rescue Errno::ECONNRESET
print "x"
c_sock.close
Thread.exit
rescue Errno::ECONNABORTED
print "x"
c_sock.close
Thread.exit
rescue => bang
puts "!!! Error (???) in Client Communication:"
puts bang
puts bang.class
puts bang.backtrace c_sock.close
Thread.exit
end
if missing_credentials or request.connection_close? or resp.content_length < 0 or max_loop > 4
c_sock.close
Thread.exit
end
max_loop += 1
end
}
end
}
end
|
#stop ⇒ Object
111
112
113
114
115
116
117
118
119
120
121
122
123
|
# File 'lib/watobo/interceptor/proxy.rb', line 111
def stop()
begin
puts "[#{self.class}] stop"
if @t_server.respond_to? :status
puts @t_server.status
Thread.kill @t_server
@intercept_srv.close
end
rescue IOError => bang
puts bang
puts bang.backtrace if $DEBUG
end
end
|
#subscribe(event, &callback) ⇒ Object
71
72
73
|
# File 'lib/watobo/interceptor/proxy.rb', line 71
def subscribe(event, &callback)
(@event_dispatcher_listeners[event] ||= []) << callback
end
|
#watobo_srv_get(file) ⇒ Object
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
# File 'lib/watobo/interceptor/proxy.rb', line 25
def watobo_srv_get(file)
srv_file = file.empty? ? File.join(@srv_path, 'index.html') : File.join(@srv_path, file)
if File.exist? srv_file
ct = case srv_file
when /\.ico/
"image/vnd.microsoft.icon"
when /\.htm/
'text/html; charset=iso-8859-1'
else
'text/plain'
end
= ["HTTP/1.0 200 OK", "Server: Watobo-Interceptor", "Connection: close", "Content-Type: #{ct}"]
content = File.open(srv_file, "rb").read
content.gsub!('WATOBO_VERSION', Watobo::VERSION)
content.gsub!('WATOBO_HOME', Watobo.working_directory)
<< "Content-Length: #{content.length}"
r = .join("\r\n")
r << "\r\n\r\n"
r << content
return r
end
= ["HTTP/1.0 404 Not Found", "Server: Watobo-Interceptor", "Connection: close", "Content-Type: text/plain; charset=iso-8859-1"]
content = "The requested file (#{file}) does not exist in the interceptor web folder."
<< "Content-Length: #{content.length}"
r = .join("\r\n")
r << "\r\n\r\n"
r << content
return r
end
|