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:
parent
21cdaa4f39
commit
e8226f9d40
@ -7,4 +7,28 @@ function postInfo(path, data) {
|
||||
|
||||
xmlHttp.open('POST', path, false);
|
||||
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();
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'erb'
|
||||
require 'cgi'
|
||||
require 'rex/exploitation/js'
|
||||
|
||||
###
|
||||
@ -16,6 +17,9 @@ module Msf
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
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(
|
||||
%w{
|
||||
CLIENT_IP
|
||||
@ -72,10 +76,14 @@ module Msf
|
||||
[
|
||||
OptBool.new('Retries', [false, "Allow the browser to retry the module", true])
|
||||
], Exploit::Remote::BrowserExploitServer)
|
||||
|
||||
register_advanced_options([
|
||||
OptString.new('CookieName', [false, "The name of the tracking cookie", DEFAULT_COOKIE_NAME])
|
||||
], Exploit::Remote::BrowserExploitServer)
|
||||
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
|
||||
#
|
||||
@ -191,7 +199,7 @@ module Msf
|
||||
|
||||
#
|
||||
# Returns the target profile based on the tag. Each profile has the following structure:
|
||||
# 'cookie' =>
|
||||
# 'cookie_name' =>
|
||||
# {
|
||||
# :os_name => 'Windows',
|
||||
# :os_flavor => 'something'
|
||||
@ -238,13 +246,13 @@ module Msf
|
||||
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
|
||||
#
|
||||
def init_profile(tag)
|
||||
sync do
|
||||
@target_profiles[tag] = {}
|
||||
@target_profiles[tag] ||= {}
|
||||
end
|
||||
end
|
||||
|
||||
@ -257,14 +265,18 @@ module Msf
|
||||
# @param request [Rex::Proto::Http::Request] The HTTP request sent by the browser
|
||||
#
|
||||
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?
|
||||
# Browser probably doesn't allow cookies, plan B :-/
|
||||
vprint_status("No cookie received, resorting to headers hash.")
|
||||
ip = cli.peerhost
|
||||
os = request.headers['User-Agent']
|
||||
tag = Rex::Text.md5("#{ip}#{os}")
|
||||
end
|
||||
else
|
||||
vprint_status("Received cookie '#{tag}'.")
|
||||
end
|
||||
|
||||
tag
|
||||
end
|
||||
@ -278,22 +290,20 @@ module Msf
|
||||
#
|
||||
def process_browser_info(source, cli, 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)
|
||||
init_profile(tag)
|
||||
|
||||
# Gathering target info from the detection stage
|
||||
case source
|
||||
when :script
|
||||
# Gathers target data from a POST request
|
||||
update_profile(target_info, :source, 'script')
|
||||
raw = Rex::Text.uri_decode(Rex::Text.decode_base64(request.body))
|
||||
raw.split('&').each do |item|
|
||||
k, v = item.scan(/(\w+)=(.*)/).flatten
|
||||
update_profile(target_info, k.to_sym, v)
|
||||
end
|
||||
parsed_body = CGI::parse(request.body || '')
|
||||
|
||||
# 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
|
||||
# Gathers target data from headers
|
||||
# This may be less accurate, and most likely less info.
|
||||
@ -379,9 +389,7 @@ module Msf
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
var query = objToQuery(d);
|
||||
postInfo("<%=get_resource.chomp("/")%>/<%=@info_receiver_page%>/", query);
|
||||
window.location = "<%=get_resource.chomp("/")%>/<%=@exploit_receiver_page%>/";
|
||||
postForm("<%=get_resource.chomp("/")%>/<%=@info_receiver_page%>/", d);
|
||||
}
|
||||
|).result(binding())
|
||||
|
||||
@ -399,6 +407,11 @@ module Msf
|
||||
|
|
||||
end
|
||||
|
||||
# @return [String] name of the tracking cookie
|
||||
def cookie_name
|
||||
datastore['CookieName'] || DEFAULT_COOKIE_NAME
|
||||
end
|
||||
|
||||
#
|
||||
# Handles exploit stages.
|
||||
#
|
||||
@ -421,14 +434,14 @@ module Msf
|
||||
ua = request.headers['User-Agent']
|
||||
init_profile(tag)
|
||||
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}/
|
||||
#
|
||||
# The detection code will hit this if Javascript is enabled
|
||||
#
|
||||
process_browser_info(source=:script, cli, request)
|
||||
send_response(cli, '')
|
||||
send_redirect(cli, "#{get_resource.chomp("/")}/#{@exploit_receiver_page}")
|
||||
|
||||
when /#{@noscript_receiver_page}/
|
||||
#
|
||||
|
Loading…
Reference in New Issue
Block a user