lib/metasploit/aggregator/tlv/uuid.rb in metasploit-aggregator-0.1.2 vs lib/metasploit/aggregator/tlv/uuid.rb in metasploit-aggregator-0.1.3

- old
+ new

@@ -7,269 +7,269 @@ module Metasploit module Aggregator module Tlv class UUID - include Rex::Arch - # - # Constants - # + include Rex::Arch + # + # Constants + # - Architectures = { - 0 => nil, - 1 => ARCH_X86, - 2 => ARCH_X64, # removed ARCH_X86_64, now consistent across the board - 3 => ARCH_X64, - 4 => ARCH_MIPS, - 5 => ARCH_MIPSLE, - 6 => ARCH_MIPSBE, - 7 => ARCH_PPC, - 8 => ARCH_PPC64, - 9 => ARCH_CBEA, - 10 => ARCH_CBEA64, - 11 => ARCH_SPARC, - 12 => ARCH_ARMLE, - 13 => ARCH_ARMBE, - 14 => ARCH_CMD, - 15 => ARCH_PHP, - 16 => ARCH_TTY, - 17 => ARCH_JAVA, - 18 => ARCH_RUBY, - 19 => ARCH_DALVIK, - 20 => ARCH_PYTHON, - 21 => ARCH_NODEJS, - 22 => ARCH_FIREFOX, - 23 => ARCH_ZARCH, - 24 => ARCH_AARCH64, - 25 => ARCH_MIPS64, - 26 => ARCH_PPC64LE - } + Architectures = { + 0 => nil, + 1 => ARCH_X86, + 2 => ARCH_X64, # removed ARCH_X86_64, now consistent across the board + 3 => ARCH_X64, + 4 => ARCH_MIPS, + 5 => ARCH_MIPSLE, + 6 => ARCH_MIPSBE, + 7 => ARCH_PPC, + 8 => ARCH_PPC64, + 9 => ARCH_CBEA, + 10 => ARCH_CBEA64, + 11 => ARCH_SPARC, + 12 => ARCH_ARMLE, + 13 => ARCH_ARMBE, + 14 => ARCH_CMD, + 15 => ARCH_PHP, + 16 => ARCH_TTY, + 17 => ARCH_JAVA, + 18 => ARCH_RUBY, + 19 => ARCH_DALVIK, + 20 => ARCH_PYTHON, + 21 => ARCH_NODEJS, + 22 => ARCH_FIREFOX, + 23 => ARCH_ZARCH, + 24 => ARCH_AARCH64, + 25 => ARCH_MIPS64, + 26 => ARCH_PPC64LE + } - Platforms = { - 0 => nil, - 1 => 'windows', - 2 => 'netware', - 3 => 'android', - 4 => 'java', - 5 => 'ruby', - 6 => 'linux', - 7 => 'cisco', - 8 => 'solaris', - 9 => 'osx', - 10 => 'bsd', - 11 => 'openbsd', - 12 => 'bsdi', - 13 => 'netbsd', - 14 => 'freebsd', - 15 => 'aix', - 16 => 'hpux', - 17 => 'irix', - 18 => 'unix', - 19 => 'php', - 20 => 'js', - 21 => 'python', - 22 => 'nodejs', - 23 => 'firefox' - } + Platforms = { + 0 => nil, + 1 => 'windows', + 2 => 'netware', + 3 => 'android', + 4 => 'java', + 5 => 'ruby', + 6 => 'linux', + 7 => 'cisco', + 8 => 'solaris', + 9 => 'osx', + 10 => 'bsd', + 11 => 'openbsd', + 12 => 'bsdi', + 13 => 'netbsd', + 14 => 'freebsd', + 15 => 'aix', + 16 => 'hpux', + 17 => 'irix', + 18 => 'unix', + 19 => 'php', + 20 => 'js', + 21 => 'python', + 22 => 'nodejs', + 23 => 'firefox' + } - # The raw length of the UUID structure - RawLength = 16 + # The raw length of the UUID structure + RawLength = 16 - # The base64url-encoded length of the UUID structure - UriLength = 22 + # The base64url-encoded length of the UUID structure + UriLength = 22 - # Validity constraints for UUID timestamps in UTC - TimestampMaxFuture = Time.now.utc.to_i + (30*24*3600) # Up to 30 days in the future - TimestampMaxPast = 1420070400 # Since 2015-01-01 00:00:00 UTC + # Validity constraints for UUID timestamps in UTC + TimestampMaxFuture = Time.now.utc.to_i + (30*24*3600) # Up to 30 days in the future + TimestampMaxPast = 1420070400 # Since 2015-01-01 00:00:00 UTC - # - # Class Methods - # + # + # Class Methods + # - # - # Parse a raw 16-byte payload UUID and return the payload ID, platform, architecture, and timestamp - # - # @param raw [String] The raw 16-byte payload UUID to parse - # @return [Hash] A hash containing the Payload ID, platform, architecture, and timestamp - # - def self.parse_raw(raw) - if raw.to_s.length < 16 - raise ArgumentError, "Raw UUID must be at least 16 bytes" + # + # Parse a raw 16-byte payload UUID and return the payload ID, platform, architecture, and timestamp + # + # @param raw [String] The raw 16-byte payload UUID to parse + # @return [Hash] A hash containing the Payload ID, platform, architecture, and timestamp + # + def self.parse_raw(raw) + if raw.to_s.length < 16 + raise ArgumentError, "Raw UUID must be at least 16 bytes" + end + + puid, plat_xor, arch_xor, plat_id, arch_id, tstamp = raw.unpack('a8C4N') + plat = find_platform_name(plat_xor ^ plat_id) + arch = find_architecture_name(arch_xor ^ arch_id) + time_xor = [plat_xor, arch_xor, plat_xor, arch_xor].pack('C4').unpack('N').first + time = time_xor ^ tstamp + { puid: puid, platform: plat, arch: arch, timestamp: time, xor1: plat_xor, xor2: arch_xor } end - puid, plat_xor, arch_xor, plat_id, arch_id, tstamp = raw.unpack('a8C4N') - plat = find_platform_name(plat_xor ^ plat_id) - arch = find_architecture_name(arch_xor ^ arch_id) - time_xor = [plat_xor, arch_xor, plat_xor, arch_xor].pack('C4').unpack('N').first - time = time_xor ^ tstamp - { puid: puid, platform: plat, arch: arch, timestamp: time, xor1: plat_xor, xor2: arch_xor } - end + # + # Filter out UUIDs with obviously invalid fields and return either + # a validated UUID or a UUID with the arch, platform, and timestamp + # fields strippped out. + # + # @param uuid [Hash] The UUID in hash format + # @return [Hash] The filtered UUID in hash format + # + def self.filter_invalid(uuid) + # Verify the UUID fields and return just the Payload ID unless the + # timestamp is within our constraints and the UUID has either a + # valid architecture or platform + if uuid[:timestamp] > TimestampMaxFuture || + uuid[:timestamp] < TimestampMaxPast || + (uuid[:arch].nil? && uuid[:platform].nil?) + return { puid: uuid[:puid] } + end + uuid + end - # - # Filter out UUIDs with obviously invalid fields and return either - # a validated UUID or a UUID with the arch, platform, and timestamp - # fields strippped out. - # - # @param uuid [Hash] The UUID in hash format - # @return [Hash] The filtered UUID in hash format - # - def self.filter_invalid(uuid) - # Verify the UUID fields and return just the Payload ID unless the - # timestamp is within our constraints and the UUID has either a - # valid architecture or platform - if uuid[:timestamp] > TimestampMaxFuture || - uuid[:timestamp] < TimestampMaxPast || - (uuid[:arch].nil? && uuid[:platform].nil?) - return { puid: uuid[:puid] } + # + # Look up the numeric platform ID given a string or PlatformList as input + # + # @param platform [String] The name of the platform to lookup + # @return [Fixnum] The integer value of this platform + # + def self.find_platform_id(platform) + name = name.first if name.kind_of? ::Array + ( Platforms.keys.select{ |k| + Platforms[k] == name + }.first || Platforms[0] ).to_i end - uuid - end - # - # Look up the numeric platform ID given a string or PlatformList as input - # - # @param platform [String] The name of the platform to lookup - # @return [Fixnum] The integer value of this platform - # - def self.find_platform_id(platform) - name = name.first if name.kind_of? ::Array - ( Platforms.keys.select{ |k| - Platforms[k] == name - }.first || Platforms[0] ).to_i - end + # + # Look up the numeric architecture ID given a string as input + # + # @param name [String] The name of the architecture to lookup + # @return [Fixnum] The integer value of this architecture + # + def self.find_architecture_id(name) + name = name.first if name.kind_of? ::Array + ( Architectures.keys.select{ |k| + Architectures[k] == name + }.first || Architectures[0] ).to_i + end - # - # Look up the numeric architecture ID given a string as input - # - # @param name [String] The name of the architecture to lookup - # @return [Fixnum] The integer value of this architecture - # - def self.find_architecture_id(name) - name = name.first if name.kind_of? ::Array - ( Architectures.keys.select{ |k| - Architectures[k] == name - }.first || Architectures[0] ).to_i - end + def self.find_platform_name(num) + Platforms[num] + end - def self.find_platform_name(num) - Platforms[num] - end + def self.find_architecture_name(num) + Architectures[num] + end - def self.find_architecture_name(num) - Architectures[num] - end + # + # Instance methods + # - # - # Instance methods - # + def initialize(opts=nil) + opts = load_new if opts.nil? + opts = load_raw(opts[:raw]) if opts[:raw] - def initialize(opts=nil) - opts = load_new if opts.nil? - opts = load_raw(opts[:raw]) if opts[:raw] + self.puid = opts[:puid] + self.timestamp = opts[:timestamp] + self.arch = opts[:arch] + self.platform = opts[:platform] + self.xor1 = opts[:xor1] + self.xor2 = opts[:xor2] - self.puid = opts[:puid] - self.timestamp = opts[:timestamp] - self.arch = opts[:arch] - self.platform = opts[:platform] - self.xor1 = opts[:xor1] - self.xor2 = opts[:xor2] + # Generate some sensible defaults + self.puid ||= SecureRandom.random_bytes(8) + self.xor1 ||= rand(256) + self.xor2 ||= rand(256) + self.timestamp ||= Time.now.utc.to_i + end - # Generate some sensible defaults - self.puid ||= SecureRandom.random_bytes(8) - self.xor1 ||= rand(256) - self.xor2 ||= rand(256) - self.timestamp ||= Time.now.utc.to_i - end + # + # Initializes a UUID object given a raw 16+ byte blob + # + # @param raw [String] The string containing at least 16 bytes of encoded data + # @return [Hash] The attributes encoded into this UUID + # + def load_raw(raw) + self.class.filter_invalid(self.class.parse_raw(raw)) + end - # - # Initializes a UUID object given a raw 16+ byte blob - # - # @param raw [String] The string containing at least 16 bytes of encoded data - # @return [Hash] The attributes encoded into this UUID - # - def load_raw(raw) - self.class.filter_invalid(self.class.parse_raw(raw)) - end + def load_new + self.class.parse_raw(self.class.generate_raw()) + end - def load_new - self.class.parse_raw(self.class.generate_raw()) - end + # + # Provides a string representation of a UUID + # + # @return [String] The human-readable version of the UUID data + # + def to_s + arch_id = self.class.find_architecture_id(self.arch).to_s + plat_id = self.class.find_platform_id(self.platform).to_s + [ + self.puid_hex, + [ self.arch || "noarch", arch_id ].join("="), + [ self.platform || "noplatform", plat_id ].join("="), + Time.at(self.timestamp.to_i).utc.strftime("%Y-%m-%dT%H:%M:%SZ") + ].join("/") + end - # - # Provides a string representation of a UUID - # - # @return [String] The human-readable version of the UUID data - # - def to_s - arch_id = self.class.find_architecture_id(self.arch).to_s - plat_id = self.class.find_platform_id(self.platform).to_s - [ - self.puid_hex, - [ self.arch || "noarch", arch_id ].join("="), - [ self.platform || "noplatform", plat_id ].join("="), - Time.at(self.timestamp.to_i).utc.strftime("%Y-%m-%dT%H:%M:%SZ") - ].join("/") - end + # + # Return a string that represents the Meterpreter arch/platform + # + def session_type + # mini-patch for x86 so that it renders x64 instead. This is + # mostly to keep various external modules happy. + arch = self.arch + if arch == ARCH_X86_64 + arch = ARCH_X64 + end + "#{arch}/#{self.platform}" + end - # - # Return a string that represents the Meterpreter arch/platform - # - def session_type - # mini-patch for x86 so that it renders x64 instead. This is - # mostly to keep various external modules happy. - arch = self.arch - if arch == ARCH_X86_64 - arch = ARCH_X64 + # + # Provides a hash representation of a UUID + # + # @return [Hash] The hash representation of the UUID suitable for creating a new one + # + def to_h + { + puid: self.puid, + arch: self.arch, platform: self.platform, + timestamp: self.timestamp, + xor1: self.xor1, xor2: self.xor2 + } end - "#{arch}/#{self.platform}" - end - # - # Provides a hash representation of a UUID - # - # @return [Hash] The hash representation of the UUID suitable for creating a new one - # - def to_h - { - puid: self.puid, - arch: self.arch, platform: self.platform, - timestamp: self.timestamp, - xor1: self.xor1, xor2: self.xor2 - } - end + # + # Provides a raw byte representation of a UUID + # + # @return [String] The 16-byte raw encoded version of the UUID + # + def to_raw + self.class.generate_raw(self.to_h) + end - # - # Provides a raw byte representation of a UUID - # - # @return [String] The 16-byte raw encoded version of the UUID - # - def to_raw - self.class.generate_raw(self.to_h) - end + # + # Provides a hex representation of the Payload UID of the UUID + # + # @return [String] The 16-byte hex string representing the Payload UID + # + def puid_hex + self.puid.unpack('H*').first + end - # - # Provides a hex representation of the Payload UID of the UUID - # - # @return [String] The 16-byte hex string representing the Payload UID - # - def puid_hex - self.puid.unpack('H*').first - end + # + # Clears the two random XOR keys used for obfuscation + # + def xor_reset + self.xor1 = self.xor2 = nil + self + end - # - # Clears the two random XOR keys used for obfuscation - # - def xor_reset - self.xor1 = self.xor2 = nil - self + attr_accessor :arch + attr_accessor :platform + attr_accessor :timestamp + attr_accessor :puid + attr_accessor :xor1 + attr_accessor :xor2 end - - attr_accessor :arch - attr_accessor :platform - attr_accessor :timestamp - attr_accessor :puid - attr_accessor :xor1 - attr_accessor :xor2 - end end end end