1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-10-29 18:07:27 +01:00

Use a keyed cookie. Moves AJAX call to a form post.

This commit is contained in:
Joe Vennix 2014-03-02 19:47:24 -06:00
parent 21cdaa4f39
commit e8226f9d40
2 changed files with 56 additions and 19 deletions

View File

@ -7,4 +7,28 @@ function postInfo(path, data) {
xmlHttp.open('POST', path, false); xmlHttp.open('POST', path, false);
xmlHttp.send(data); xmlHttp.send(data);
}
function postForm(path, data) {
var set = function(obj, attr, val) {
if (obj.setAttribute) { obj.setAttribute(attr, val); }
else { obj[attr] = val; }
}
var form = document.createElement('form');
set(form, 'method', 'POST');
set(form, 'action', path);
var input;
for (var i in data) {
input = document.createElement('input')
set(input, 'type', 'hidden');
set(input, 'name', i);
set(input, 'value', data[i]);
form.appendChild(input);
}
form.style.display = 'none';
document.body.appendChild(form);
form.submit();
} }

View File

@ -1,6 +1,7 @@
# -*- coding: binary -*- # -*- coding: binary -*-
require 'erb' require 'erb'
require 'cgi'
require 'rex/exploitation/js' require 'rex/exploitation/js'
### ###
@ -16,6 +17,9 @@ module Msf
include Msf::Exploit::Remote::HttpServer::HTML include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::RopDb include Msf::Exploit::RopDb
# this must be static between runs, otherwise the older cookies will be ignored
DEFAULT_COOKIE_NAME = '__ua'
PROXY_REQUEST_HEADER_SET = Set.new( PROXY_REQUEST_HEADER_SET = Set.new(
%w{ %w{
CLIENT_IP CLIENT_IP
@ -72,10 +76,14 @@ module Msf
[ [
OptBool.new('Retries', [false, "Allow the browser to retry the module", true]) OptBool.new('Retries', [false, "Allow the browser to retry the module", true])
], Exploit::Remote::BrowserExploitServer) ], Exploit::Remote::BrowserExploitServer)
register_advanced_options([
OptString.new('CookieName', [false, "The name of the tracking cookie", DEFAULT_COOKIE_NAME])
], Exploit::Remote::BrowserExploitServer)
end end
# #
# Syncs a block of code # Allows a block of code to access BES resources in a thread-safe fashion
# #
# @param block [Proc] Block of code to sync # @param block [Proc] Block of code to sync
# #
@ -191,7 +199,7 @@ module Msf
# #
# Returns the target profile based on the tag. Each profile has the following structure: # Returns the target profile based on the tag. Each profile has the following structure:
# 'cookie' => # 'cookie_name' =>
# { # {
# :os_name => 'Windows', # :os_name => 'Windows',
# :os_flavor => 'something' # :os_flavor => 'something'
@ -238,13 +246,13 @@ module Msf
end end
# #
# Initializes a profile # Initializes a profile, if it did not previously exist
# #
# @param tag [String] A unique string as a way to ID the profile # @param tag [String] A unique string as a way to ID the profile
# #
def init_profile(tag) def init_profile(tag)
sync do sync do
@target_profiles[tag] = {} @target_profiles[tag] ||= {}
end end
end end
@ -257,14 +265,18 @@ module Msf
# @param request [Rex::Proto::Http::Request] The HTTP request sent by the browser # @param request [Rex::Proto::Http::Request] The HTTP request sent by the browser
# #
def retrieve_tag(request) def retrieve_tag(request)
tag = request.headers['Cookie'].to_s cookie = CGI::Cookie.parse(request.headers['Cookie'].to_s)
tag = cookie.has_key?(cookie_name) && cookie[cookie_name].first
if tag.blank? if tag.blank?
# Browser probably doesn't allow cookies, plan B :-/ # Browser probably doesn't allow cookies, plan B :-/
vprint_status("No cookie received, resorting to headers hash.")
ip = cli.peerhost ip = cli.peerhost
os = request.headers['User-Agent'] os = request.headers['User-Agent']
tag = Rex::Text.md5("#{ip}#{os}") tag = Rex::Text.md5("#{ip}#{os}")
end else
vprint_status("Received cookie '#{tag}'.")
end
tag tag
end end
@ -278,22 +290,20 @@ module Msf
# #
def process_browser_info(source, cli, request) def process_browser_info(source, cli, request)
tag = retrieve_tag(request) tag = retrieve_tag(request)
# Browser doesn't allow cookies. Can't track that, use a different way to track.
init_profile(tag) if request.headers['Cookie'].blank?
target_info = get_profile(tag) target_info = get_profile(tag)
init_profile(tag)
# Gathering target info from the detection stage # Gathering target info from the detection stage
case source case source
when :script when :script
# Gathers target data from a POST request # Gathers target data from a POST request
update_profile(target_info, :source, 'script') update_profile(target_info, :source, 'script')
raw = Rex::Text.uri_decode(Rex::Text.decode_base64(request.body)) parsed_body = CGI::parse(request.body || '')
raw.split('&').each do |item|
k, v = item.scan(/(\w+)=(.*)/).flatten
update_profile(target_info, k.to_sym, v)
end
# CGI::parse returns a single-value array for every value,
# let's just collaps that to the value itself
vprint_status("Received sniffed browser data over POST: \n#{parsed_body}.")
parsed_body.each { |k, v| update_profile(target_info, k.to_sym, v.first) }
when :headers when :headers
# Gathers target data from headers # Gathers target data from headers
# This may be less accurate, and most likely less info. # This may be less accurate, and most likely less info.
@ -379,9 +389,7 @@ module Msf
<% end %> <% end %>
<% end %> <% end %>
var query = objToQuery(d); postForm("<%=get_resource.chomp("/")%>/<%=@info_receiver_page%>/", d);
postInfo("<%=get_resource.chomp("/")%>/<%=@info_receiver_page%>/", query);
window.location = "<%=get_resource.chomp("/")%>/<%=@exploit_receiver_page%>/";
} }
|).result(binding()) |).result(binding())
@ -399,6 +407,11 @@ module Msf
| |
end end
# @return [String] name of the tracking cookie
def cookie_name
datastore['CookieName'] || DEFAULT_COOKIE_NAME
end
# #
# Handles exploit stages. # Handles exploit stages.
# #
@ -421,14 +434,14 @@ module Msf
ua = request.headers['User-Agent'] ua = request.headers['User-Agent']
init_profile(tag) init_profile(tag)
html = get_detection_html(ua) html = get_detection_html(ua)
send_response(cli, html, {'Set-Cookie' => tag}) send_response(cli, html, {'Set-Cookie' => "#{cookie_name}=#{tag}"})
when /#{@info_receiver_page}/ when /#{@info_receiver_page}/
# #
# The detection code will hit this if Javascript is enabled # The detection code will hit this if Javascript is enabled
# #
process_browser_info(source=:script, cli, request) process_browser_info(source=:script, cli, request)
send_response(cli, '') send_redirect(cli, "#{get_resource.chomp("/")}/#{@exploit_receiver_page}")
when /#{@noscript_receiver_page}/ when /#{@noscript_receiver_page}/
# #