# -*- 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