lib/msf/core/payload/uuid/options.rb
# -*- coding => binary -*-
#
# This module provides datastore option definitions and helper methods for payload modules that support UUIDs
#
module Msf::Payload::UUID::Options
include Rex::Payloads::Meterpreter::UriChecksum
def initialize(info = {})
super
register_advanced_options(
[
Msf::OptString.new('PayloadUUIDSeed', [ false, 'A string to use when generating the payload UUID (deterministic)']),
Msf::OptString.new('PayloadUUIDRaw', [ false, 'A hex string representing the raw 8-byte PUID value for the UUID']),
Msf::OptString.new('PayloadUUIDName', [ false, 'A human-friendly name to reference this unique payload (requires tracking)']),
Msf::OptBool.new('PayloadUUIDTracking', [ true, 'Whether or not to automatically register generated UUIDs', false]),
], self.class)
end
#
# Generates a URI with a given checksum and optionally with an embedded UUID if
# the desired length can accommodate it.
#
# @param mode [Symbol] The type of checksum to generate (:connect, :init_native, :init_python, :init_java)
# @param len [Integer] The length of the URI not including the leading slash, optionally nil for random
# @return [String] A URI with a leading slash that hashes to the checksum, with an optional UUID
#
def generate_uri_uuid_mode(mode, len = nil, uuid: nil)
sum = uri_checksum_lookup(mode)
# The URI length may not have room for an embedded UUID
if len && len < URI_CHECKSUM_UUID_MIN_LEN
# Throw an error if the user set a seed, but there is no room for it
if datastore['PayloadUUIDSeed'].to_s.length > 0 || datastore['PayloadUUIDRaw'].to_s.length > 0
raise ArgumentError, "A PayloadUUIDSeed or PayloadUUIDRaw value was specified, but this payload doesn't have enough room for a UUID"
end
return "/" + generate_uri_checksum(sum, len, prefix="")
end
uuid ||= generate_payload_uuid
uri = generate_uri_uuid(sum, uuid, len)
record_payload_uuid_url(uuid, uri)
uri
end
# Generate a Payload UUID
def generate_payload_uuid(conf = {})
conf[:arch] ||= self.arch
conf[:platform] ||= self.platform
# Handle user-specified seed values
if datastore['PayloadUUIDSeed'].to_s.length > 0
conf[:seed] = datastore['PayloadUUIDSeed'].to_s
end
# Handle user-specified raw payload UID values
if datastore['PayloadUUIDRaw'].to_s.length > 0
puid_raw = [datastore['PayloadUUIDRaw'].to_s].pack("H*")
if puid_raw.length != 8
raise ArgumentError, "The PayloadUUIDRaw value must be exactly 16 bytes of hex"
end
conf.delete(:seed)
conf[:puid] = puid_raw
end
if datastore['PayloadUUIDName'].to_s.length > 0 && ! datastore['PayloadUUIDTracking']
raise ArgumentError, "The PayloadUUIDName value is ignored unless PayloadUUIDTracking is enabled"
end
# Generate the UUID object
uuid = Msf::Payload::UUID.new(conf)
record_payload_uuid(uuid)
uuid
end
# Store a UUID in the JSON database if tracking is enabled
def record_payload_uuid(uuid, info={})
return unless datastore['PayloadUUIDTracking']
# skip if there is no active database
return if !(framework.db && framework.db.active)
uuid_info = info.merge({
uuid: uuid.puid_hex,
arch: uuid.arch,
platform: uuid.platform,
timestamp: uuid.timestamp,
})
if datastore['PayloadUUIDSeed'].to_s.length > 0
uuid_info[:seed] = datastore['PayloadUUIDSeed']
end
if datastore['PayloadUUIDName'].to_s.length > 0
uuid_info[:name] = datastore['PayloadUUIDName']
end
framework.db.create_payload(uuid_info)
end
# Store a UUID URL in the database if tracking is enabled
def record_payload_uuid_url(uuid, url)
return unless datastore['PayloadUUIDTracking']
# skip if there is no active database
if (framework.db && framework.db.active)
payload_info = {
uuid: uuid.puid_hex,
}
payload = framework.db.payloads(payload_info).first
unless payload.nil?
urls = payload.urls.nil? ? [] : payload.urls
urls << url
urls.uniq!
framework.db.update_payload({id: payload.id, urls: urls})
end
else
print_warning('Without a database connected that payload UUID tracking will not work!')
end
end
end