Class: Watobo::HTTPSocket::Agent

Inherits:
Object
  • Object
show all
Defined in:
lib/watobo/http_socket/agent.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::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 Method Summary collapse

Constructor Details

#initialize(session_id, prefs = {}) ⇒ Agent

INITIALIZE

Possible preferences: :proxy => '127.0.0.1:port' :valid_sids => Hash.new, :sid_patterns => [], :logout_signatures => [], :update_valid_sids => false, :update_sids => false, :update_contentlength => true


400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/watobo/http_socket/agent.rb', line 400

def initialize( session_id, prefs={} )
  
  @connection = nil

  session = nil

  session = ( session_id.is_a? Fixnum ) ? session_id : session_id.object_id
  session = Digest::MD5.hexdigest(Time.now.to_f.to_s) if session_id.nil?

  unless @@settings.has_key? session
    @@settings[session] = {
      :valid_sids => Hash.new,
      :sid_patterns => [],
      # :valid_csrf_tokens => Hash.new,
      :csrf_patterns => [],
      :csrf_requests => [],
      :logout_signatures => [],
      :logout_content_types => Hash.new,
      :update_valid_sids => false,
      :update_sids => false,
      :update_session => true,
      :update_contentlength => true,
      :login_chats => [],
      :www_auth => Hash.new,
      :client_certificates => {},
      :proxy_auth => Hash.new
    }
  end
  @session = @@settings[session] # shortcut to settings
  @session.update prefs

  #  @valid_csrf_tokens = Hash.new

  addProxy( prefs[:proxy] ) if prefs.is_a? Hash and prefs[:proxy]

  @ctx = OpenSSL::SSL::SSLContext.new()
  @ctx.key = nil
  @ctx.cert = nil

  # TODO: Implement switches for URL-Encoding (http://www.blooberry.com/indexdot/html/topics/urlencoding.htm)
  # TODO: Implement switches for Following Redirects
  # TODO: Implement switches for Logging, Debugging, ...
end

Instance Method Details

#addProxy(prefs = nil) ⇒ Object


363
364
365
366
367
368
369
370
371
372
373
374
375
376
# File 'lib/watobo/http_socket/agent.rb', line 363

def addProxy(prefs=nil)

  proxy = nil
  unless prefs.nil?
    proxy = Proxy.new(prefs)
  #  proxy.setCredentials(prefs[:credentials]) unless prefs[:credentials].nil?
    unless prefs[:site].nil?
      @@proxy[prefs[:site]] = proxy
      return
    end
  end

  @@proxy[:default] = proxy
end

#connected?Boolean

Returns:

  • (Boolean)

62
63
64
# File 'lib/watobo/http_socket/agent.rb', line 62

def connected?
  !@connection.nil?
end

#doRequest(request, opts = {}) ⇒ Object

+++ doRequest(request) +++ + function:


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
# File 'lib/watobo/http_socket/agent.rb', line 267

def doRequest(request, opts={} )
  begin
    @session.update opts
  #  puts "[doRequest] #{@session.to_yaml}"
    # puts "#[#{self.class}]" + @session[:csrf_requests].first.object_id.to_s
    unless @session[:csrf_requests].empty? or @session[:csrf_patterns].empty?
      csrf_cache = Hash.new
      @session[:csrf_requests].each do |req|
        copy = Watobo::Request.new YAML.load(YAML.dump(req))

        updateCSRFToken(csrf_cache, copy)
        socket, csrf_request, csrf_response = sendHTTPRequest(copy, opts)
        next if socket.nil?
      #  puts "= Response Headers:"
      #  puts csrf_response
      #  puts "==="
        update_sids(csrf_request.host, csrf_response.headers)
        next if socket.nil?
        #  p "*"
        #    csrf_response = readHTTPHeader(socket)
        readHTTPBody(socket, csrf_response, csrf_request, opts)

        next if csrf_response.body.nil?
        update_sids(csrf_request.host, [csrf_response.body])

        updateCSRFCache(csrf_cache, csrf_request, [csrf_response.body]) if csrf_response.content_type =~ /text\//

        # socket.close
        closeSocket(socket)
      end
      #p @session[:csrf_requests].length
      updateCSRFToken(csrf_cache, request)
    end

    socket, request, response = sendHTTPRequest(request, opts)

    if socket.nil?
      return request, response
    end

    update_sids(request.host, response.headers) if @session[:update_sids] == true
    
    if @session[:follow_redirect]
 # puts response.status
  if response.status =~ /^302/
    response.extend Watobo::Mixin::Parser::Web10
    request.extend Watobo::Mixin::Shaper::Web10

    loc_header = response.headers("Location:").first
    new_location = loc_header.gsub(/^[^:]*:/,'').strip
    unless new_location =~ /^http/
new_location = request.proto + "://" + request.site + "/" + request.dir + "/" + new_location.sub(/^[\.\/]*/,'')
    end
    
    notify(:follow_redirect, new_location)
    nr = Watobo::Request.new YAML.load(YAML.dump(request))
    
    # create GET request for new location
    nr.replaceMethod("GET")
    nr.removeHeader("Content-Length")
    nr.removeBody()
    nr.replaceURL(new_location)

   
    socket, request, response = sendHTTPRequest(nr, opts)
   
    if socket.nil?
#return nil, request
return request, response
    end
  end
end

    readHTTPBody(socket, response, request, opts)

    unless response.body.nil?
      update_sids(request.host, [response.body]) if @session[:update_sids] == true and response.content_type =~ /text\//
    end

    #socket.close
    closeSocket(socket)

  rescue  => bang
    #  puts "! Error in doRequest"
    puts "! Module #{Module.nesting[0].name}"
    puts bang
    #  puts bang.backtrace if $DEBUG
    @lasterror = bang
    # raise
    # ensure
  end

  response.extend Watobo::Mixin::Parser::Web10
  return request, response
end

#get_settingsObject


378
379
380
# File 'lib/watobo/http_socket/agent.rb', line 378

def get_settings
  @@settings
end

#getProxy(site = nil) ⇒ Object


382
383
384
385
386
387
# File 'lib/watobo/http_socket/agent.rb', line 382

def getProxy(site=nil)
  unless site.nil?
    return @@proxy[site] unless @@proxy[site].nil?
  end
  return @@proxy[:default]
end

#runLogin(chat_list, prefs = {}) ⇒ Object


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
56
57
58
59
60
# File 'lib/watobo/http_socket/agent.rb', line 31

def runLogin(chat_list, prefs={})
  @@login_mutex.synchronize do
    begin
      @@login_in_progress = true
       = Hash.new
      .update prefs
      dummy = {:ignore_logout => true, :update_sids => true, :update_session => true, :update_contentlength => true}
      .update dummy
      puts "! Start Login ..." if $DEBUG
      unless chat_list.empty?
        #  puts login_prefs.to_yaml
        chat_list.each do |chat|
          print "! LoginRequest: #{chat.id}" if $DEBUG
          test_req = chat.copyRequest
          request, response = doRequest(test_req, )
        end
      else
        puts "! no login script configured !"
      end
    rescue => bang
      puts "!ERROR in runLogin"
      puts bang.backtrace if $DEBUG
    ensure
      @@login_in_progress = false
      @@login_cv.signal
      # exit
      #  print "L]"
    end
  end
end

#send(request, prefs = {}) ⇒ Object

sendHTTPRequest


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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
# File 'lib/watobo/http_socket/agent.rb', line 71

def send(request, prefs={})
#Watobo.print_debug("huhule", "#{prefs.to_yaml}", "gagagag")
  begin
    @lasterror = nil
    response_header = nil
    
   
    # update current preferences, prefs given here are stronger then global settings!
    current_prefs = Hash.new
    [:update_session, :update_sids, :update_contentlength, :ssl_cipher, :www_auth, :client_certificates].each do |k|
      current_prefs[k] = prefs[k].nil? ? @session[k] : prefs[k]
    end

    updateSession(request) if current_prefs[:update_session] == true

    #---------------------------------------
    request.removeHeader("^Proxy-Connection") #if not use_proxy
    #request.removeHeader("^Connection") #if not use_proxy
    request.removeHeader("^Accept-Encoding")
    # If-Modified-Since: Tue, 28 Oct 2008 11:06:43 GMT
    # If-None-Match: W/"3975-1225192003000"
    request.removeHeader("^If-")
    #  puts
    #  request.each do |line|
    #  puts line.unpack("H*")
    #end
    #puts
    if current_prefs[:update_contentlength] == true then
      request.fix_content_length()
    end

    #request.add_header("Via", "Watobo") if use_proxy
    #puts request
    # puts "=============="
  rescue SocketError
    puts "!!! unknown hostname #{host}"
    puts request.first
    return nil, "WATOBO: Could not resolve hostname #{host}", nil
  rescue => bang
    puts bang
    puts bang.backtrace if $DEBUG
  end
  
  begin
    unless proxy.nil?
      # connection requires proxy
      # puts "* use proxy #{proxy.name}"

      # check for regular proxy authentication
      if request.is_ssl?
        socket, response_header = sslProxyConnect(request, proxy, current_prefs)
        return socket, response_header, error_response("Could Not Connect To Proxy: #{proxy.name} (#{proxy.host}:#{proxy.port})\n", "#{response_header}") if socket.nil?
        
        if current_prefs[:www_auth].has_key?(site)
          case current_prefs[:www_auth][site][:type]
            when AUTH_TYPE_NTLM
            #  puts "* found NTLM credentials for site #{site}"
              socket, response_header = wwwAuthNTLM(socket, request, current_prefs[:www_auth][site])

            else
              puts "* Unknown Authentication Type: #{current_prefs[:www_auth][site][:type]}"
            end
        else
          
          data = request.join + "\r\n"
          unless socket.nil?
            socket.print data
            response_header = readHTTPHeader(socket, current_prefs)
          end
        end
        return socket, request, response_header
      end
      #  puts "* doProxyRequest"
      socket, response_header = doProxyRequest(request, proxy, current_prefs)
      #   puts socket.class
      return socket, response_header, error_response("Could Not Connect To Proxy: #{proxy.name} (#{proxy.host}:#{proxy.port})\n", "#{response_header}") if socket.nil?

      return socket, request, response_header
    else
      # direct connection to host
      tcp_socket = nil
      #  timeout(6) do
      #puts "* no proxy - direct connection"
      tcp_socket = TCPSocket.new( host, port )
      tcp_socket.setsockopt( Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1)
      tcp_socket.sync = true

      socket =  tcp_socket
      if request.is_ssl?
        ssl_prefs = {}
        ssl_prefs[:ssl_cipher] = current_prefs[:ssl_cipher] if current_prefs.has_key? :ssl_cipher
        if current_prefs.has_key? :client_certificates
          if current_prefs[:client_certificates].has_key? request.site
            puts "* use ssl client certificate for site #{request.site}" if $DEBUG
            ssl_prefs[:ssl_client_cert] = current_prefs[:client_certificates][request.site][:ssl_client_cert] 
          ssl_prefs[:ssl_client_key] = current_prefs[:client_certificates][request.site][:ssl_client_key]
          end
        end
        socket = sslConnect(tcp_socket, ssl_prefs)
      end
      #puts socket.class
      # remove URI before sending request but cache it for restoring request
      uri_cache = nil
      uri_cache = request.removeURI #if proxy.nil?

      
     # request.addHeader("Proxy-Connection", "Close") unless proxy.nil?
     # request.addHeader("Accept-Encoding", "gzip;q=0;identity; q=0.5, *;q=0") #don't want encoding
      

      if current_prefs[:www_auth].has_key?(site)
        case current_prefs[:www_auth][site][:type]
        when AUTH_TYPE_NTLM
          # puts "* found NTLM credentials for site #{site}"
          socket, response_header = wwwAuthNTLM(socket, request, current_prefs[:www_auth][site])
          request.restoreURI(uri_cache)
        
        else
          puts "* Unknown Authentication Type: #{current_prefs[:www_auth][site][:type]}"
        end
      else
        # puts "========== Add Headers"
       # request.addHeader("Connection", "Close") #if not use_proxy

        data = request.join
        unless request.has_body? 
          data << "\r\n" unless data =~ /\r\n\r\n$/ 
        end
       # puts "= SESSION ="
       # puts data
       # puts data.unpack("H*")[0].gsub(/0d0a/,"0d0a\n")
        
        unless socket.nil?                
          socket.print data
         # if socket.is_a? OpenSSL::SSL::SSLSocket
         #   socket.io.shutdown(Socket::SHUT_WR)
         # else
         #   socket.shutdown(Socket::SHUT_WR)
         # end
          response_header = readHTTPHeader(socket, current_prefs)
        end
        # RESTORE URI FOR HISTORY/LOG
        request.restoreURI(uri_cache)

      end
      return socket, Watobo::Request.new(request), Watobo::Response.new(response_header)
    end

  rescue Errno::ECONNREFUSED
    response = error_response "connection refused (#{host}:#{port})"
    puts response
    socket = nil
  rescue Errno::ECONNRESET
    response = error_response "connection reset (#{host}:#{port})"
    socket = nil
  rescue Errno::ECONNABORTED
    response = error_response "connection aborted (#{host}:#{port})"
    socket = nil
  rescue Errno::EHOSTUNREACH
    response = error_response "host unreachable (#{host}:#{port})"
    socket = nil
  rescue Timeout::Error
    #request = "WATOBO: TimeOut (#{host}:#{port})\n"
    response = error_response "TimeOut (#{host}:#{port})"
    socket = nil
  rescue Errno::ETIMEDOUT
    response = error_response "TimeOut (#{host}:#{port})"
    socket = nil
  rescue Errno::ENOTCONN
    puts "!!!ENOTCONN"
  rescue OpenSSL::SSL::SSLError
    response = error_response "SSL-Error", $!.backtrace.join
    socket = nil
  rescue => bang
    response = error_response "ERROR:", "#{bang}\n#{bang.backtrace}"
    socket = nil

    puts bang
    puts bang.backtrace if $DEBUG
  end
  puts response
  return socket, request, response
end

#setSIDCache(new_cache = {}) ⇒ Object


260
261
262
# File 'lib/watobo/http_socket/agent.rb', line 260

def setSIDCache(new_cache = {} )
  @session[:valid_sids] = new_cache if new_cache.is_a? Hash
end

#sidCacheObject


255
256
257
258
# File 'lib/watobo/http_socket/agent.rb', line 255

def sidCache()
  #puts @project
  @session[:valid_sids]
end