Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/rex/payloads/meterpreter/uri_checksum.rb
Views: 11655
# -*- coding: binary -*-12module Rex3module Payloads4module Meterpreter5module UriChecksum67#8# Define 8-bit checksums for matching URLs9# These are based on charset frequency10#11URI_CHECKSUM_INITW = 92 # Windows12URI_CHECKSUM_INITN = 92 # Native (same as Windows)13URI_CHECKSUM_INITP = 80 # Python14URI_CHECKSUM_INITJ = 88 # Java15URI_CHECKSUM_CONN = 98 # Existing session16URI_CHECKSUM_INIT_CONN = 95 # New stageless session1718# Mapping between checksums and modes19URI_CHECKSUM_MODES = Hash[20URI_CHECKSUM_INITN, :init_native,21URI_CHECKSUM_INITP, :init_python,22URI_CHECKSUM_INITJ, :init_java,23URI_CHECKSUM_INIT_CONN, :init_connect,24URI_CHECKSUM_CONN, :connect25]2627URI_CHECKSUM_MIN_LEN = 52829# Limit how long :connect URLs are to stay within 256 bytes when including30# the hostname, colon, port, and leading slash31URI_CHECKSUM_CONN_MAX_LEN = 1283233URI_CHECKSUM_UUID_MIN_LEN = URI_CHECKSUM_MIN_LEN + Msf::Payload::UUID::UriLength3435# Map "random" URIs to static strings, allowing us to randomize36# the URI sent in the first request.37#38# @param uri [String] The URI string from the HTTP request39# @return [Hash] The attributes extracted from the URI40def process_uri_resource(uri)4142# Ignore non-base64url characters in the URL43uri_bare = uri.gsub(/[^a-zA-Z0-9_\-]/, '')4445# Figure out the mode based on the checksum46uri_csum = Rex::Text.checksum8(uri_bare)4748# Extract the UUID if the URI is long enough49uri_uuid = nil50if uri_bare.length >= URI_CHECKSUM_UUID_MIN_LEN51uri_uuid = Msf::Payload::UUID.new(uri: uri_bare)52end5354uri_mode = URI_CHECKSUM_MODES[uri_csum]5556# Return a hash of URI attributes57{ uri: uri_bare, sum: uri_csum, uuid: uri_uuid, mode: uri_mode }58end5960# Create a URI that matches the specified checksum and payload uuid61#62# @param sum [Integer] A checksum mode value to use for the generated url63# @param uuid [Msf::Payload::UUID] A valid UUID object64# @param len [Integer] An optional URI length value, including the leading slash65# @return [String] The URI string for connections66def generate_uri_uuid(sum, uuid, len=nil)67curl_uri_len = URI_CHECKSUM_UUID_MIN_LEN + rand(URI_CHECKSUM_CONN_MAX_LEN - URI_CHECKSUM_UUID_MIN_LEN)68curl_prefix = uuid.to_uri6970if len71# Subtract a byte to take into account the leading /72curl_uri_len = len - 173end7475if curl_uri_len < URI_CHECKSUM_UUID_MIN_LEN76raise ArgumentError, "Length must be #{URI_CHECKSUM_UUID_MIN_LEN+1} bytes or greater"77end7879# Pad out the URI and make the checksum match the specified sum80"/" + generate_uri_checksum(sum, curl_uri_len, curl_prefix)81end8283# Create an arbitrary length URI that matches a given checksum84#85# @param sum [Integer] The checksum value that the generated URI should match86# @param len [Integer] The length of the URI to generate87# @param prefix [String] The optional prefix to use to build the URI88# @return [String] The URI string that checksums to the given value89def generate_uri_checksum(sum, len=5, prefix="")90# Lengths shorter than 4 bytes are unable to match all possible checksums91# Lengths of exactly 4 are relatively slow to find for high checksum values92# Lengths of 5 or more bytes find a matching checksum fairly quickly (~80ms)93if len < URI_CHECKSUM_MIN_LEN94raise ArgumentError, "Length must be #{URI_CHECKSUM_MIN_LEN} bytes or greater"95end9697gen_len = len-prefix.length98if gen_len < URI_CHECKSUM_MIN_LEN99raise ArgumentError, "Prefix must be at least {URI_CHECKSUM_MIN_LEN} bytes smaller than total length"100end101102# Brute force a matching checksum for shorter URIs103if gen_len < 40104loop do105uri = prefix + Rex::Text.rand_text_base64url(gen_len)106return uri if Rex::Text.checksum8(uri) == sum107end108end109110# The rand_text_base64url() method becomes a bottleneck at around 40 bytes111# Calculating a static prefix flattens out the average runtime for longer URIs112prefix << Rex::Text.rand_text_base64url(gen_len-20)113114loop do115uri = prefix + Rex::Text.rand_text_base64url(20)116return uri if Rex::Text.checksum8(uri) == sum117end118end119120# Return the numerical checksum for a given mode symbol121#122# @param mode [Symbol] The mode symbol to lookup (:connect, :init_native, :init_python, :init_java)123# @return [Integer] The URI checksum value corresponding with the mode124def uri_checksum_lookup(mode)125sum = URI_CHECKSUM_MODES.keys.select{|ksum| URI_CHECKSUM_MODES[ksum] == mode}.first126unless sum127raise ArgumentError, "Unknown checksum mode: #{mode}"128end129sum130end131end132end133end134end135136137