127 lines
4.3 KiB
Ruby
127 lines
4.3 KiB
Ruby
# -*- 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
|
|
|