General

  • Target

    https://pixeldrain.com/u/4ZKPNzu4

  • Sample

    241006-ydk3yssarq

Malware Config

Extracted

Path

C:\metasploit\apps\pro\vendor\bundle\ruby\3.0.0\gems\metasploit-framework-6.3.17\documentation\modules\auxiliary\admin\kerberos\inspect_ticket.md

Ransom Note
## Inspecting Kerberos Tickets The `auxiliary/admin/kerberos/inspect_ticket` module allows you to print the contents of a ccache/kirbi file. The module will output ticket information such as: - Client information - Service information - Ticket creation / expiry times - Decrypted ticket contents - if `NTHASH` or `AESKEY` is set ## Acquiring tickets Kerberos tickets can be acquired from multiple sources. For instance: - Retrieved directly from the KDC with the `get_ticket` module - Forged using the `forge_ticket` module after compromising the krbtgt or a service account's encryption keys - Extracted from memory using Meterpreter and mimikatz: ```msf meterpreter > load kiwi Loading extension kiwi... .#####. mimikatz 2.2.0 20191125 (x64/windows) .## ^ ##. "A La Vie, A L'Amour" - (oe.eo) ## / \ ## /*** Benjamin DELPY `gentilkiwi` ( [email protected] ) ## \ / ## > http://blog.gentilkiwi.com/mimikatz '## v ##' Vincent LE TOUX ( [email protected] ) '#####' > http://pingcastle.com / http://mysmartlogon.com ***/ Success. meterpreter > kiwi_cmd "sekurlsa::tickets /export" Authentication Id : 0 ; 1393218 (00000000:00154242) Session : Network from 0 User Name : DC3$ Domain : DEMO Logon Server : (null) Logon Time : 1/12/2023 9:11:00 PM SID : S-1-5-18 * Username : DC3$ * Domain : DEMO.LOCAL * Password : (null) Group 0 - Ticket Granting Service Group 1 - Client Ticket ? [00000000] Start/End/MaxRenew: 1/12/2023 7:41:41 PM ; 1/13/2023 5:37:45 AM ; 1/1/1601 12:00:00 AM Service Name (02) : LDAP ; DC3 ; @ DEMO.LOCAL Target Name (--) : @ DEMO.LOCAL Client Name (01) : DC3$ ; @ DEMO.LOCAL Flags 40a50000 : name_canonicalize ; ok_as_delegate ; pre_authent ; renewable ; forwardable ; Session Key : 0x00000012 - aes256_hmac ab64d555f18de6a3262d921e6dc75dcf884852f551db3114f7983dbaf276e1d6 Ticket : 0x00000012 - aes256_hmac ; kvno = 7 [...] ==================== Base64 of file : [0;154242][email protected] ==================== doQAAAYXMIQAAAYRoIQAAAADAgEFoYQAAAADAgEWooQAAAS2MIQAAASwYYQAAASq MIQAAASkoIQAAAADAgEFoYQAAAAMGwpBREYzLkxPQ0FMooQAAAAmMIQAAAAgoIQA AAADAgECoYQAAAARMIQAAAALGwRMREFQGwNEQzOjhAAABFcwhAAABFGghAAAAAMC ... etc... ==================== ``` Note that tools often Base64 encode the Kirbi content to display to the user. However the `inspect_ticket` module expects the input file to be in binary format. To convert base64 strings to binary files: ``` # Linux cat ticket.b64 | base64 -d > ticket.kirbi # Mac cat ticket.b64 | base64 -D > ticket.kirbi # Powershell [IO.File]::WriteAllBytes("ticket.kirbi", [Convert]::FromBase64String("<bas64_ticket>")) ``` ## Module usage 1. Start msfconsole 2. Do: `use auxiliary/admin/kerberos/inspect_ticket` 3. Do: `set TICKET_PATH /path/to/ccache/file` 4. Optional: either `set AES_KEY aes_key_here` or `set NTHASH nthash_here` - which will attempt to decrypt tickets 5. Do: `run` to see the contents of the ticket ## Scenarios ### Inspecting Ticket contents This action allows you to see the contents of any ccache or kirbi file, If you are able to provide the decryption key we can also show the encrypted parts of the tickets. 1. `TICKET_PATH` - The path to the ccache or kirbi file. 2. `AES_KEY` - (Optional) Only set this if you have the decryption key and it is an AES128 or AES256 key. 3. `NTHASH` - (Optional) Only set this if you have the decryption key and it is an NTHASH. No other options are used in this action. **Without Key** ```msf msf6 auxiliary(admin/kerberos/inspect_ticket) > run TICKET_PATH=/path/to/ticket Primary Principal: [email protected] Ccache version: 4 Creds: 1 Credential[0]: Server: cifs/[email protected] Client: [email protected] Ticket etype: 18 (AES256) Key: 3436643936633032656264663030393931323461366635653364393932613763 Ticket Length: 978 Subkey: false Addresses: 0 Authdatas: 0 Times: Auth time: 2022-11-21 13:52:00 +0000 Start time: 2022-11-21 13:52:00 +0000 End time: 2032-11-18 13:52:00 +0000 Renew Till: 2032-11-18 13:52:00 +0000 Ticket: Ticket Version Number: 5 Realm: WINDOMAIN.LOCAL Server Name: cifs/dc.windomain.local Encrypted Ticket Part: Ticket etype: 18 (AES256) Key Version Number: 2 Cipher: 1YrnB+fhzeLEq+4NUcXvoEsSI29+gwCDg3qjYdb0YHhqx23BhZGOK9rIQ99uXeuLHSapJAanCE9g/PyyKDE1kggrEHfy6cxwsP25exmN2w3NXVm7P0PqMVON2RBp2S11eIdF/Zibhrs7JbaaVw0Hv8GpbpHdFI0l6Xx3Jz+y0bqFsFNEsU8nEW35Z3Oo2xpI/xTwNTyG1Bmg+bktSLyI6nEPtJXQKcoJTrNhSBNsZ18HZiUPim9EqSCHUh0VbDeLntryh+lt0TIgwhwipHPWnro+Y81dvX5j8ZeBdgKgnoX3jciU629u/RveQJgyw/vLk1KT0RzTbHSwdRk/xi6ghccvew33TKJ8q3nP/JuSWDzaDE6I6v3KgInSZP+XkCAV5VT//U49MtIVIKARcmtXQwVxztMXKlWjIaxQwl9BN6CuyWZjDcafAssjPWgWIAsesmEWHn3btv1BP0a4gvn5f1b7Fu4Gh6w0ARCryxZkSl+6UhJbcdaRT23WhqN24ECGEl0VIX4fuLs6x0gVtAQ2YsI+HkoQYuI+C28gXzJUCac6rJyFQSTsciwj/jVf18ttw1vfGGKa/BVcqscGZoJPpBiuGPBkIbeAOery0Sjn+0tP0tsPYw1OkpzZ7n/j/YdmTX6UAFZjCLbgvF8hoPyider1gntOiSjlLlEUITLTfe5zqWi4gs47Ly6lvggBWW9Yg0fIaPOHYMvsszMLcJz0+dFXtDVI452LIEatLDvp1aKkwGANWYyRgOMlHR3fD030SOTNEb5oa6WigWZQLlhuDbgrfFaWWAMp7opcNbNKy7Iv17EscL7pW2Ygc38VbmbFtdIfvpQ9niwLr2msjzhB7RPihZXcUAlVygLwykq0JDG4fRmoNXzNydbnYlX9E+KW0fHFjoBitAx1xrp9p5Ajwoyy+wIk0mt/aC4pbfcoRjt4GUF/9DhZnH3HiPn4lM9TLMzpiediEtDZtKgGvAAP2cJZn2gsLRlKAtBZvl+ibe1uDzC9g6rnObAx3c+OSG9rmHzBBCq6D8wW6ZjrQy8njNuriC5rnQxUpVhgGvTOkeTphSIHX+D4SuMd+XZ4zqa3DsrHzIeVWAvrTHCDBzy+DKt2RoQTwYmGT+a0YB0btQtgIfRj2OwDtlP65JUxC+/ANelHg73d0REoYistB5ZMmvk= ``` **With Key** ```msf msf6 auxiliary(admin/kerberos/inspect_ticket) > run AES_KEY=4b912be0366a6f37f4a7d571bee18b1173d93195ef76f8d1e3e81ef6172ab326 TICKET_PATH=/path/to/ticket Primary Principal: [email protected] Ccache version: 4 Creds: 1 Credential[0]: Server: cifs/[email protected] Client: [email protected] Ticket etype: 18 (AES256) Key: 3436643936633032656264663030393931323461366635653364393932613763 Ticket Length: 978 Subkey: false Addresses: 0 Authdatas: 0 Times: Auth time: 2022-11-21 13:52:00 +0000 Start time: 2022-11-21 13:52:00 +0000 End time: 2032-11-18 13:52:00 +0000 Renew Till: 2032-11-18 13:52:00 +0000 Ticket: Ticket Version Number: 5 Realm: WINDOMAIN.LOCAL Server Name: cifs/dc.windomain.local Encrypted Ticket Part: Ticket etype: 18 (AES256) Key Version Number: 2 Decrypted (with key: \x4b\x91\x2b\xe0\x36\x6a\x6f\x37\xf4\xa7\xd5\x71\xbe\xe1\x8b\x11\x73\xd9\x31\x95\xef\x76\xf8\xd1\xe3\xe8\x1e\xf6\x17\x2a\xb3\x26): Times: Auth time: 2022-11-21 13:52:00 UTC Start time: 2022-11-21 13:52:00 UTC End time: 2032-11-18 13:52:00 UTC Renew Till: 2032-11-18 13:52:00 UTC Client Addresses: 0 Transited: tr_type: 0, Contents: "" Client Name: 'Administrator' Client Realm: 'WINDOMAIN.LOCAL' Ticket etype: 18 (AES256) Encryption Key: 3436643936633032656264663030393931323461366635653364393932613763 Flags: 0x50a00000 (FORWARDABLE, PROXIABLE, RENEWABLE, PRE_AUTHENT) PAC: Validation Info: Logon Time: 2022-11-21 13:52:00 +0000 Logoff Time: Never Expires (inf) Kick Off Time: Never Expires (inf) Password Last Set: No Time Set (0) Password Can Change: No Time Set (0) Password Must Change: Never Expires (inf) Logon Count: 0 Bad Password Count: 0 User ID: 500 Primary Group ID: 513 User Flags: 0 User Session Key: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 User Account Control: 528 Sub Auth Status: 0 Last Successful Interactive Logon: No Time Set (0) Last Failed Interactive Logon: No Time Set (0) Failed Interactive Logon Count: 0 SID Count: 0 Resource Group Count: 0 Group Count: 5 Group IDs: Relative ID: 513, Attributes: 7 Relative ID: 512, Attributes: 7 Relative ID: 520, Attributes: 7 Relative ID: 518, Attributes: 7 Relative ID: 519, Attributes: 7 Logon Domain ID: S-1-5-21-3541430928-2051711210-1391384369 Effective Name: 'Administrator' Full Name: '' Logon Script: '' Profile Path: '' Home Directory: '' Home Directory Drive: '' Logon Server: '' Logon Domain Name: 'WINDOMAIN.LOCAL' Client Info: Name: 'Administrator' Client ID: 2022-11-21 13:52:00 +0000 Pac Server Checksum: Signature: \x04\xe5\xab\x06\x1c\x7a\x90\x9a\x26\xb1\x22\xc2 Pac Privilege Server Checksum: Signature: \x71\x0b\xb1\x83\x85\x82\x57\xf4\x10\x21\xbd\x7e ``` Both of these examples are printing the contents of the same ccache file and showing the difference in output if you have the decryption key available.
URLs

http://blog.gentilkiwi.com/mimikatz

http://pingcastle.com

http://mysmartlogon.com

Extracted

Path

C:\metasploit\apps\pro\vendor\bundle\ruby\3.0.0\gems\metasploit-framework-6.3.17\lib\rex\post\meterpreter\packet.rb

Ransom Note
# -*- coding: binary -*- require 'openssl' require 'rex/post/meterpreter/command_mapper' module Rex module Post module Meterpreter # # Constants # PACKET_TYPE_REQUEST = 0 PACKET_TYPE_RESPONSE = 1 PACKET_TYPE_PLAIN_REQUEST = 10 PACKET_TYPE_PLAIN_RESPONSE = 11 # # TLV Meta Types # TLV_META_TYPE_NONE = 0 TLV_META_TYPE_STRING = (1 << 16) TLV_META_TYPE_UINT = (1 << 17) TLV_META_TYPE_RAW = (1 << 18) TLV_META_TYPE_BOOL = (1 << 19) TLV_META_TYPE_QWORD = (1 << 20) TLV_META_TYPE_COMPRESSED = (1 << 29) TLV_META_TYPE_GROUP = (1 << 30) TLV_META_TYPE_COMPLEX = (1 << 31) # Exclude compressed from the mask since other meta types (e.g. RAW) can also # be compressed TLV_META_MASK = ( TLV_META_TYPE_STRING | TLV_META_TYPE_UINT | TLV_META_TYPE_RAW | TLV_META_TYPE_BOOL | TLV_META_TYPE_QWORD | TLV_META_TYPE_GROUP | TLV_META_TYPE_COMPLEX ) # # TLV base starting points # TLV_RESERVED = 0 TLV_EXTENSIONS = 20000 TLV_USER = 40000 TLV_TEMP = 60000 # # TLV Specific Types # TLV_TYPE_ANY = TLV_META_TYPE_NONE | 0 TLV_TYPE_COMMAND_ID = TLV_META_TYPE_UINT | 1 TLV_TYPE_REQUEST_ID = TLV_META_TYPE_STRING | 2 TLV_TYPE_EXCEPTION = TLV_META_TYPE_GROUP | 3 TLV_TYPE_RESULT = TLV_META_TYPE_UINT | 4 TLV_TYPE_STRING = TLV_META_TYPE_STRING | 10 TLV_TYPE_UINT = TLV_META_TYPE_UINT | 11 TLV_TYPE_BOOL = TLV_META_TYPE_BOOL | 12 TLV_TYPE_LENGTH = TLV_META_TYPE_UINT | 25 TLV_TYPE_DATA = TLV_META_TYPE_RAW | 26 TLV_TYPE_FLAGS = TLV_META_TYPE_UINT | 27 TLV_TYPE_CHANNEL_ID = TLV_META_TYPE_UINT | 50 TLV_TYPE_CHANNEL_TYPE = TLV_META_TYPE_STRING | 51 TLV_TYPE_CHANNEL_DATA = TLV_META_TYPE_RAW | 52 TLV_TYPE_CHANNEL_DATA_GROUP = TLV_META_TYPE_GROUP | 53 TLV_TYPE_CHANNEL_CLASS = TLV_META_TYPE_UINT | 54 TLV_TYPE_CHANNEL_PARENTID = TLV_META_TYPE_UINT | 55 TLV_TYPE_SEEK_WHENCE = TLV_META_TYPE_UINT | 70 TLV_TYPE_SEEK_OFFSET = TLV_META_TYPE_UINT | 71 TLV_TYPE_SEEK_POS = TLV_META_TYPE_UINT | 72 TLV_TYPE_EXCEPTION_CODE = TLV_META_TYPE_UINT | 300 TLV_TYPE_EXCEPTION_STRING = TLV_META_TYPE_STRING | 301 TLV_TYPE_LIBRARY_PATH = TLV_META_TYPE_STRING | 400 TLV_TYPE_TARGET_PATH = TLV_META_TYPE_STRING | 401 TLV_TYPE_MIGRATE_PID = TLV_META_TYPE_UINT | 402 TLV_TYPE_MIGRATE_PAYLOAD = TLV_META_TYPE_RAW | 404 TLV_TYPE_MIGRATE_ARCH = TLV_META_TYPE_UINT | 405 TLV_TYPE_MIGRATE_BASE_ADDR = TLV_META_TYPE_UINT | 407 TLV_TYPE_MIGRATE_ENTRY_POINT = TLV_META_TYPE_UINT | 408 TLV_TYPE_MIGRATE_SOCKET_PATH = TLV_META_TYPE_STRING | 409 TLV_TYPE_MIGRATE_STUB = TLV_META_TYPE_RAW | 411 TLV_TYPE_LIB_LOADER_NAME = TLV_META_TYPE_STRING | 412 TLV_TYPE_LIB_LOADER_ORDINAL = TLV_META_TYPE_UINT | 413 TLV_TYPE_TRANS_TYPE = TLV_META_TYPE_UINT | 430 TLV_TYPE_TRANS_URL = TLV_META_TYPE_STRING | 431 TLV_TYPE_TRANS_UA = TLV_META_TYPE_STRING | 432 TLV_TYPE_TRANS_COMM_TIMEOUT = TLV_META_TYPE_UINT | 433 TLV_TYPE_TRANS_SESSION_EXP = TLV_META_TYPE_UINT | 434 TLV_TYPE_TRANS_CERT_HASH = TLV_META_TYPE_RAW | 435 TLV_TYPE_TRANS_PROXY_HOST = TLV_META_TYPE_STRING | 436 TLV_TYPE_TRANS_PROXY_USER = TLV_META_TYPE_STRING | 437 TLV_TYPE_TRANS_PROXY_PASS = TLV_META_TYPE_STRING | 438 TLV_TYPE_TRANS_RETRY_TOTAL = TLV_META_TYPE_UINT | 439 TLV_TYPE_TRANS_RETRY_WAIT = TLV_META_TYPE_UINT | 440 TLV_TYPE_TRANS_HEADERS = TLV_META_TYPE_STRING | 441 TLV_TYPE_TRANS_GROUP = TLV_META_TYPE_GROUP | 442 TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460 TLV_TYPE_UUID = TLV_META_TYPE_RAW | 461 TLV_TYPE_SESSION_GUID = TLV_META_TYPE_RAW | 462 TLV_TYPE_RSA_PUB_KEY = TLV_META_TYPE_RAW | 550 TLV_TYPE_SYM_KEY_TYPE = TLV_META_TYPE_UINT | 551 TLV_TYPE_SYM_KEY = TLV_META_TYPE_RAW | 552 TLV_TYPE_ENC_SYM_KEY = TLV_META_TYPE_RAW | 553 # # Pivots # TLV_TYPE_PIVOT_ID = TLV_META_TYPE_RAW | 650 TLV_TYPE_PIVOT_STAGE_DATA = TLV_META_TYPE_RAW | 651 TLV_TYPE_PIVOT_NAMED_PIPE_NAME = TLV_META_TYPE_STRING | 653 # # Core flags # LOAD_LIBRARY_FLAG_ON_DISK = (1 << 0) LOAD_LIBRARY_FLAG_EXTENSION = (1 << 1) LOAD_LIBRARY_FLAG_LOCAL = (1 << 2) # # Sane defaults # GUID_SIZE = 16 NULL_GUID = "\x00" * GUID_SIZE def self.generate_command_id_map_c id_map = CommandMapper.get_commands(*%w{ core stdapi priv extapi sniffer winpmem kiwi unhook espia incognito python powershell lanattacks peinjector }) command_ids = id_map.map {|k, v| "#define COMMAND_ID_#{k.upcase} #{v}"} %Q^ /*! * @file common_command_ids.h * @brief Declarations of command ID values * @description This file was generated #{::Time.now.utc}. Do not modify directly. */ #ifndef _METERPRETER_SOURCE_COMMON_COMMAND_IDS_H #define _METERPRETER_SOURCE_COMMON_COMMAND_IDS_H #{command_ids.join("\n")} #endif ^ end def self.generate_command_id_map_java id_map = CommandMapper.get_commands(*%w{ core stdapi }) command_ids = id_map.map {|k, v| " public static final int #{k.upcase} = #{v};"} %Q^ package com.metasploit.meterpreter.command; /** * All supported Command Identifiers * * @author Genereated by a tool @ #{::Time.now.utc} */ public interface CommandId { #{command_ids.join("\n")} } ^ end def self.generate_command_id_map_php_lib(lib, id_map) command_ids = id_map.map {|k, v| "define('COMMAND_ID_#{k.upcase}', #{v});"} %Q^ # --------------------------------------------------------------- # --- THIS CONTENT WAS GENERATED BY A TOOL @ #{::Time.now.utc} # IDs for #{lib} #{command_ids.join("\n")} # --------------------------------------------------------------- ^ end def self.generate_command_id_map_php %Q^ #{self.generate_command_id_map_php_lib('metsrv', CommandMapper.get_commands('core'))} #{self.generate_command_id_map_php_lib('stdapi', CommandMapper.get_commands('stdapi'))} ^ end def self.generate_command_id_map_python id_map = CommandMapper.get_commands(*%w{ core stdapi }) command_ids = id_map.map {|k, v| " (#{v}, '#{k.downcase}'),"} %Q^ # --------------------------------------------------------------- # --- THIS CONTENT WAS GENERATED BY A TOOL @ #{::Time.now.utc} COMMAND_IDS = ( #{command_ids.join("\n")} ) # --------------------------------------------------------------- ^ end def self.generate_command_id_map_python_extension id_map = CommandMapper.get_commands(*%w{ core stdapi priv extapi sniffer winpmem kiwi unhook espia incognito python powershell lanattacks peinjector }) command_ids = id_map.map {|k, v| "COMMAND_ID_#{k.upcase} = #{v}"} %Q^ # --------------------------------------------------------------- # --- THIS CONTENT WAS GENERATED BY A TOOL @ #{::Time.now.utc} #{command_ids.join("\n")} # --------------------------------------------------------------- ^ end def self.generate_command_id_map_csharp id_map = CommandMapper.get_commands(*%w{ core stdapi priv extapi sniffer winpmem kiwi unhook espia incognito python powershell lanattacks peinjector }) command_ids = id_map.map {|k, v| "#{k.split('_').map(&:capitalize).join} = #{v},"} %Q^ /// <summary> // This content was generated by a tool @ #{::Time.now.utc} /// </summary> namespace MSF.Powershell.Meterpreter { public enum CommandId { #{command_ids.join("\n ")} } } ^ end ### # # Base TLV (Type-Length-Value) class # ### class Tlv attr_accessor :type, :value, :compress HEADER_SIZE = 8 ## # # Constructor # ## # # Returns an instance of a TLV. # def initialize(type, value = nil, compress=false) @type = type @compress = compress if (value != nil) if (type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING) if (value.kind_of?(Integer)) @value = value.to_s else @value = value.dup end else @value = value end end end def _tlv_type_string(value) tlv_names = ::Rex::Post::Meterpreter::CommandMapper.get_tlv_names(value).map { |name| name.to_s.gsub('TLV_TYPE_', '').gsub('PACKET_TYPE_', '') } case tlv_names.length when 0 "unknown-#{value}" when 1 tlv_names.first else # In the off-chance we have multiple TLV types which have the same value # https://github.com/rapid7/metasploit-framework/issues/16267 # Sort it to ensure consistency across tests "oneOf(#{tlv_names.sort_by(&:to_s).join(',')})" end end def inspect utype = type ^ TLV_META_TYPE_COMPRESSED group = false meta = case (utype & TLV_META_MASK) when TLV_META_TYPE_STRING; "STRING" when TLV_META_TYPE_UINT; "INT" when TLV_META_TYPE_RAW; "RAW" when TLV_META_TYPE_BOOL; "BOOL" when TLV_META_TYPE_QWORD; "QWORD" when TLV_META_TYPE_GROUP; group=true; "GROUP" when TLV_META_TYPE_COMPLEX; "COMPLEX" else; 'unknown-meta-type' end stype = case type when PACKET_TYPE_REQUEST; 'Request' when PACKET_TYPE_RESPONSE; 'Response' else; _tlv_type_string(type) end val = value.inspect if val.length > 50 val = val[0,50] + ' ..."' end group ||= (self.class.to_s =~ /Packet/) if group has_command_ids = type == PACKET_TYPE_RESPONSE && (self.method == COMMAND_ID_CORE_ENUMEXTCMD || self.method == COMMAND_ID_CORE_LOADLIB) if has_command_ids longest_command_id = self.get_tlvs(TLV_TYPE_UINT).map(&:value).max longest_command_id_length = longest_command_id.to_s.length end tlvs_inspect = "tlvs=[\n" @tlvs.each { |t| if t.type == TLV_TYPE_UINT && has_command_ids && longest_command_id_length command_name = ::Rex::Post::Meterpreter::CommandMapper.get_command_name(t.value) command_output = "command=#{command_name}>\n" this_value_length = t.value.to_s.length adjusted_command_name = command_output.rjust(command_output.length + longest_command_id_length - this_value_length) tlvs_inspect << " #{t.inspect.gsub(/>$/, '')} " << adjusted_command_name else tlvs_inspect << " #{t.inspect}\n" end } tlvs_inspect << "]" else tlvs_inspect = "meta=#{meta.ljust(10)} value=#{val}" if type == TLV_TYPE_COMMAND_ID begin command_name = ::Rex::Post::Meterpreter::CommandMapper.get_command_name(value) rescue command_name = nil end tlvs_inspect <<= " command=#{command_name || 'unknown'}" end end "#<#{self.class} type=#{stype.ljust(15)} #{tlvs_inspect}>" end ## # # Conditionals # ## # # Checks to see if a TLVs meta type is equivalent to the meta type passed. # def meta_type?(meta) return (self.type & meta == meta) end # # Checks to see if the TLVs type is equivalent to the type passed. # def type?(type) return self.type == type end # # Checks to see if the TLVs value is equivalent to the value passed. # def value?(value) return self.value == value end ## # # Serializers # ## # # Converts the TLV to raw. # def to_r # Forcibly convert to ASCII-8BIT encoding raw = value.to_s.unpack("C*").pack("C*") if (self.type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING) raw += "\x00" elsif (self.type & TLV_META_TYPE_UINT == TLV_META_TYPE_UINT) raw = [value].pack("N") elsif (self.type & TLV_META_TYPE_QWORD == TLV_META_TYPE_QWORD) raw = [ self.htonq( value.to_i ) ].pack("Q<") elsif (self.type & TLV_META_TYPE_BOOL == TLV_META_TYPE_BOOL) if (value == true) raw = [1].pack("c") else raw = [0].pack("c") end end # check if the tlv is to be compressed... if @compress raw_uncompressed = raw # compress the raw data raw_compressed = Rex::Text.zlib_deflate( raw_uncompressed ) # check we have actually made the raw data smaller... # (small blobs often compress slightly larger then the origional) # if the compressed data is not smaller, we dont use the compressed data if( raw_compressed.length < raw_uncompressed.length ) # if so, set the TLV's type to indicate compression is used self.type = self.type | TLV_META_TYPE_COMPRESSED # update the raw data with the uncompressed data length + compressed data # (we include the uncompressed data length as the C side will need to know this for decompression) raw = [ raw_uncompressed.length ].pack("N") + raw_compressed end end [raw.length + HEADER_SIZE, self.type].pack("NN") + raw end # # Translates the raw format of the TLV into a sanitize version. # def from_r(raw) self.value = nil length, self.type = raw.unpack("NN"); # check if the tlv value has been compressed... if( self.type & TLV_META_TYPE_COMPRESSED == TLV_META_TYPE_COMPRESSED ) # set this TLV as using compression @compress = true # remove the TLV_META_TYPE_COMPRESSED flag from the tlv type to restore the # tlv type to its origional, allowing for transparent data compression. self.type = self.type ^ TLV_META_TYPE_COMPRESSED # decompress the compressed data (skipping the length and type DWORD's) raw_decompressed = Rex::Text.zlib_inflate( raw[HEADER_SIZE..length-1] ) # update the length to reflect the decompressed data length (+HEADER_SIZE for the length and type DWORD's) length = raw_decompressed.length + HEADER_SIZE # update the raw buffer with the new length, decompressed data and updated type. raw = [length, self.type].pack("NN") + raw_decompressed end if (self.type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING) if (raw.length > 0) self.value = raw[HEADER_SIZE..length-2] else self.value = nil end elsif (self.type & TLV_META_TYPE_UINT == TLV_META_TYPE_UINT) self.value = raw.unpack("NNN")[2] elsif (self.type & TLV_META_TYPE_QWORD == TLV_META_TYPE_QWORD) self.value = raw.unpack("NNQ<")[2] self.value = self.ntohq( self.value ) elsif (self.type & TLV_META_TYPE_BOOL == TLV_META_TYPE_BOOL) self.value = raw.unpack("NNc")[2] if (self.value == 1) self.value = true else self.value = false end else self.value = raw[HEADER_SIZE..length-1] end length end protected def htonq(value) if [1].pack( 's' ) == [1].pack('n') return value else [value].pack('Q<').reverse.unpack('Q<').first end end def ntohq(value) htonq(value) end end ### # # Group TLVs contain zero or more TLVs # ### class GroupTlv < Tlv attr_accessor :tlvs ## # # Constructor # ## # # Initializes the group TLV container to the supplied type # and creates an empty TLV array. # def initialize(type) super(type) self.tlvs = [] end ## # # Group-based TLV accessors # ## # # Enumerates TLVs of the supplied type. # def each(type = TLV_TYPE_ANY, &block) get_tlvs(type).each(&block) end # # Synonym for each. # def each_tlv(type = TLV_TYPE_ANY, &block) each(type, &block) end # # Enumerates TLVs of a supplied type with indexes. # def each_with_index(type = TLV_TYPE_ANY, &block) get_tlvs(type).each_with_index(&block) end # # Synonym for each_with_index. # def each_tlv_with_index(type = TLV_TYPE_ANY, &block) each_with_index(type, block) end # # Returns an array of TLVs for the given type. # def get_tlvs(type) if type == TLV_TYPE_ANY self.tlvs else type_tlvs = [] self.tlvs.each() { |tlv| if (tlv.type?(type)) type_tlvs << tlv end } type_tlvs end end ## # # TLV management # ## # # Adds a TLV of a given type and value. # def add_tlv(type, value = nil, replace
URLs

https://github.com/rapid7/metasploit-framework/issues/16267

Extracted

Path

C:\metasploit\apps\pro\vendor\bundle\ruby\3.0.0\gems\pdf-reader-2.11.0\lib\pdf\reader\key_builder_v5.rb

Ransom Note
# coding: utf-8 # typed: strict # frozen_string_literal: true require 'digest/md5' require 'rc4' class PDF::Reader # Processes the Encrypt dict from an encrypted PDF and a user provided # password and returns a key that can decrypt the file. # # This can generate a decryption key compatible with the following standard encryption algorithms: # # * Version 5 (AESV3) # class KeyBuilderV5 def initialize(opts = {}) @key_length = 256 # hash(32B) + validation salt(8B) + key salt(8B) @owner_key = opts[:owner_key] || "" # hash(32B) + validation salt(8B) + key salt(8B) @user_key = opts[:user_key] || "" # decryption key, encrypted w/ owner password @owner_encryption_key = opts[:owner_encryption_key] || "" # decryption key, encrypted w/ user password @user_encryption_key = opts[:user_encryption_key] || "" end # Takes a string containing a user provided password. # # If the password matches the file, then a string containing a key suitable for # decrypting the file will be returned. If the password doesn't match the file, # and exception will be raised. # def key(pass) pass = pass.byteslice(0...127).to_s # UTF-8 encoded password. first 127 bytes encrypt_key = auth_owner_pass(pass) encrypt_key ||= auth_user_pass(pass) encrypt_key ||= auth_owner_pass_r6(pass) encrypt_key ||= auth_user_pass_r6(pass) raise PDF::Reader::EncryptedPDFError, "Invalid password (#{pass})" if encrypt_key.nil? encrypt_key end private # Algorithm 3.2a - Computing an encryption key # # Defined in PDF 1.7 Extension Level 3 # # if the string is a valid user/owner password, this will return the decryption key # def auth_owner_pass(password) if Digest::SHA256.digest(password + @owner_key[32..39] + @user_key) == @owner_key[0..31] cipher = OpenSSL::Cipher.new('AES-256-CBC') cipher.decrypt cipher.key = Digest::SHA256.digest(password + @owner_key[40..-1] + @user_key) cipher.iv = "\x00" * 16 cipher.padding = 0 cipher.update(@owner_encryption_key) + cipher.final end end def auth_user_pass(password) if Digest::SHA256.digest(password + @user_key[32..39]) == @user_key[0..31] cipher = OpenSSL::Cipher.new('AES-256-CBC') cipher.decrypt cipher.key = Digest::SHA256.digest(password + @user_key[40..-1]) cipher.iv = "\x00" * 16 cipher.padding = 0 cipher.update(@user_encryption_key) + cipher.final end end def auth_owner_pass_r6(password) if r6_digest(password, @owner_key[32..39].to_s, @user_key[0,48].to_s) == @owner_key[0..31] cipher = OpenSSL::Cipher.new('AES-256-CBC') cipher.decrypt cipher.key = r6_digest(password, @owner_key[40,8].to_s, @user_key[0, 48].to_s) cipher.iv = "\x00" * 16 cipher.padding = 0 cipher.update(@owner_encryption_key) + cipher.final end end def auth_user_pass_r6(password) if r6_digest(password, @user_key[32..39].to_s) == @user_key[0..31] cipher = OpenSSL::Cipher.new('AES-256-CBC') cipher.decrypt cipher.key = r6_digest(password, @user_key[40,8].to_s) cipher.iv = "\x00" * 16 cipher.padding = 0 cipher.update(@user_encryption_key) + cipher.final end end # PDF 2.0 spec, 7.6.4.3.4 # Algorithm 2.B: Computing a hash (revision 6 and later) def r6_digest(password, salt, user_key = '') k = Digest::SHA256.digest(password + salt + user_key) e = '' i = 0 while i < 64 or e.getbyte(-1).to_i > i - 32 k1 = (password + k + user_key) * 64 aes = OpenSSL::Cipher.new("aes-128-cbc").encrypt aes.key = k[0, 16].to_s aes.iv = k[16, 16].to_s aes.padding = 0 e = String.new(aes.update(k1)) k = case unpack_128bit_bigendian_int(e) % 3 when 0 then Digest::SHA256.digest(e) when 1 then Digest::SHA384.digest(e) when 2 then Digest::SHA512.digest(e) end i = i + 1 end k[0, 32].to_s end def unpack_128bit_bigendian_int(str) ints = str[0,16].to_s.unpack("N*") (ints[0].to_i << 96) + (ints[1].to_i << 64) + (ints[2].to_i << 32) + ints[3].to_i end end end

Extracted

Path

C:\metasploit\apps\pro\vendor\bundle\ruby\3.0.0\gems\aws-sdk-s3-1.120.1\lib\aws-sdk-s3\encryptionV2\client.rb

Ransom Note
# frozen_string_literal: true require 'forwardable' module Aws module S3 REQUIRED_PARAMS = [:key_wrap_schema, :content_encryption_schema, :security_profile] SUPPORTED_SECURITY_PROFILES = [:v2, :v2_and_legacy] # Provides an encryption client that encrypts and decrypts data client-side, # storing the encrypted data in Amazon S3. The `EncryptionV2::Client` (V2 Client) # provides improved security over the `Encryption::Client` (V1 Client) # by using more modern and secure algorithms. You can use the V2 Client # to continue decrypting objects encrypted using deprecated algorithms # by setting security_profile: :v2_and_legacy. The latest V1 Client also # supports reading and decrypting objects encrypted by the V2 Client. # # This client uses a process called "envelope encryption". Your private # encryption keys and your data's plain-text are **never** sent to # Amazon S3. **If you lose you encryption keys, you will not be able to # decrypt your data.** # # ## Envelope Encryption Overview # # The goal of envelope encryption is to combine the performance of # fast symmetric encryption while maintaining the secure key management # that asymmetric keys provide. # # A one-time-use symmetric key (envelope key) is generated client-side. # This is used to encrypt the data client-side. This key is then # encrypted by your master key and stored alongside your data in Amazon # S3. # # When accessing your encrypted data with the encryption client, # the encrypted envelope key is retrieved and decrypted client-side # with your master key. The envelope key is then used to decrypt the # data client-side. # # One of the benefits of envelope encryption is that if your master key # is compromised, you have the option of just re-encrypting the stored # envelope symmetric keys, instead of re-encrypting all of the # data in your account. # # ## Basic Usage # # The encryption client requires an {Aws::S3::Client}. If you do not # provide a `:client`, then a client will be constructed for you. # # require 'openssl' # key = OpenSSL::PKey::RSA.new(1024) # # # encryption client # s3 = Aws::S3::EncryptionV2::Client.new( # encryption_key: key, # key_wrap_schema: :rsa_oaep_sha1, # the key_wrap_schema must be rsa_oaep_sha1 for asymmetric keys # content_encryption_schema: :aes_gcm_no_padding, # security_profile: :v2 # use :v2_and_legacy to allow reading/decrypting objects encrypted by the V1 encryption client # ) # # # round-trip an object, encrypted/decrypted locally # s3.put_object(bucket:'aws-sdk', key:'secret', body:'handshake') # s3.get_object(bucket:'aws-sdk', key:'secret').body.read # #=> 'handshake' # # # reading encrypted object without the encryption client # # results in the getting the cipher text # Aws::S3::Client.new.get_object(bucket:'aws-sdk', key:'secret').body.read # #=> "... cipher text ..." # # ## Required Configuration # # You must configure all of the following: # # * a key or key provider - See the Keys section below. The key provided determines # the key wrapping schema(s) supported for both encryption and decryption. # * `key_wrap_schema` - The key wrapping schema. It must match the type of key configured. # * `content_encryption_schema` - The only supported value currently is `:aes_gcm_no_padding`. # More options will be added in future releases. # * `security_profile` - Determines the support for reading objects written # using older key wrap or content encryption schemas. If you need to read # legacy objects encrypted by an existing V1 Client, then set this to `:v2_and_legacy`. # Otherwise, set it to `:v2` # # ## Keys # # For client-side encryption to work, you must provide one of the following: # # * An encryption key # * A {KeyProvider} # * A KMS encryption key id # # Additionally, the key wrapping schema must agree with the type of the key: # * :aes_gcm: An AES encryption key or a key provider. # * :rsa_oaep_sha1: An RSA encryption key or key provider. # * :kms_context: A KMS encryption key id # # ### An Encryption Key # # You can pass a single encryption key. This is used as a master key # encrypting and decrypting all object keys. # # key = OpenSSL::Cipher.new("AES-256-ECB").random_key # symmetric key - used with `key_wrap_schema: :aes_gcm` # key = OpenSSL::PKey::RSA.new(1024) # asymmetric key pair - used with `key_wrap_schema: :rsa_oaep_sha1` # # s3 = Aws::S3::EncryptionV2::Client.new( # encryption_key: key, # key_wrap_schema: :aes_gcm, # or :rsa_oaep_sha1 if using RSA # content_encryption_schema: :aes_gcm_no_padding, # security_profile: :v2 # ) # # ### Key Provider # # Alternatively, you can use a {KeyProvider}. A key provider makes # it easy to work with multiple keys and simplifies key rotation. # # ### KMS Encryption Key Id # # If you pass the id of an AWS Key Management Service (KMS) key and # use :kms_content for the key_wrap_schema, then KMS will be used to # generate, encrypt and decrypt object keys. # # # keep track of the kms key id # kms = Aws::KMS::Client.new # key_id = kms.create_key.key_metadata.key_id # # Aws::S3::EncryptionV2::Client.new( # kms_key_id: key_id, # kms_client: kms, # key_wrap_schema: :kms_context, # content_encryption_schema: :aes_gcm_no_padding, # security_profile: :v2 # ) # # ## Custom Key Providers # # A {KeyProvider} is any object that responds to: # # * `#encryption_materials` # * `#key_for(materials_description)` # # Here is a trivial implementation of an in-memory key provider. # This is provided as a demonstration of the key provider interface, # and should not be used in production: # # class KeyProvider # # def initialize(default_key_name, keys) # @keys = keys # @encryption_materials = Aws::S3::EncryptionV2::Materials.new( # key: @keys[default_key_name], # description: JSON.dump(key: default_key_name), # ) # end # # attr_reader :encryption_materials # # def key_for(matdesc) # key_name = JSON.parse(matdesc)['key'] # if key = @keys[key_name] # key # else # raise "encryption key not found for: #{matdesc.inspect}" # end # end # end # # Given the above key provider, you can create an encryption client that # chooses the key to use based on the materials description stored with # the encrypted object. This makes it possible to use multiple keys # and simplifies key rotation. # # # uses "new-key" for encrypting objects, uses either for decrypting # keys = KeyProvider.new('new-key', { # "old-key" => Base64.decode64("kM5UVbhE/4rtMZJfsadYEdm2vaKFsmV2f5+URSeUCV4="), # "new-key" => Base64.decode64("w1WLio3agRWRTSJK/Ouh8NHoqRQ6fn5WbSXDTHjXMSo="), # }), # # # chooses the key based on the materials description stored # # with the encrypted object # s3 = Aws::S3::EncryptionV2::Client.new( # key_provider: keys, # key_wrap_schema: ..., # content_encryption_schema: :aes_gcm_no_padding, # security_profile: :v2 # ) # # ## Materials Description # # A materials description is JSON document string that is stored # in the metadata (or instruction file) of an encrypted object. # The {DefaultKeyProvider} uses the empty JSON document `"{}"`. # # When building a key provider, you are free to store whatever # information you need to identify the master key that was used # to encrypt the object. # # ## Envelope Location # # By default, the encryption client store the encryption envelope # with the object, as metadata. You can choose to have the envelope # stored in a separate "instruction file". An instruction file # is an object, with the key of the encrypted object, suffixed with # `".instruction"`. # # Specify the `:envelope_location` option as `:instruction_file` to # use an instruction file for storing the envelope. # # # default behavior # s3 = Aws::S3::EncryptionV2::Client.new( # key_provider: ..., # envelope_location: :metadata, # ) # # # store envelope in a separate object # s3 = Aws::S3::EncryptionV2::Client.new( # key_provider: ..., # envelope_location: :instruction_file, # instruction_file_suffix: '.instruction' # default # key_wrap_schema: ..., # content_encryption_schema: :aes_gcm_no_padding, # security_profile: :v2 # ) # # When using an instruction file, multiple requests are made when # putting and getting the object. **This may cause issues if you are # issuing concurrent PUT and GET requests to an encrypted object.** # module EncryptionV2 class Client extend Deprecations extend Forwardable def_delegators :@client, :config, :delete_object, :head_object, :build_request # Creates a new encryption client. You must configure all of the following: # # * a key or key provider - The key provided also determines the key wrapping # schema(s) supported for both encryption and decryption. # * `key_wrap_schema` - The key wrapping schema. It must match the type of key configured. # * `content_encryption_schema` - The only supported value currently is `:aes_gcm_no_padding` # More options will be added in future releases. # * `security_profile` - Determines the support for reading objects written # using older key wrap or content encryption schemas. If you need to read # legacy objects encrypted by an existing V1 Client, then set this to `:v2_and_legacy`. # Otherwise, set it to `:v2` # # To configure the key you must provide one of the following set of options: # # * `:encryption_key` # * `:kms_key_id` # * `:key_provider` # # You may also pass any other options accepted by `Client#initialize`. # # @option options [S3::Client] :client A basic S3 client that is used # to make api calls. If a `:client` is not provided, a new {S3::Client} # will be constructed. # # @option options [OpenSSL::PKey::RSA, String] :encryption_key The master # key to use for encrypting/decrypting all objects. # # @option options [String] :kms_key_id When you provide a `:kms_key_id`, # then AWS Key Management Service (KMS) will be used to manage the # object encryption keys. By default a {KMS::Client} will be # constructed for KMS API calls. Alternatively, you can provide # your own via `:kms_client`. To only support decryption/reads, you may # provide `:allow_decrypt_with_any_cmk` which will use # the implicit CMK associated with the data during reads but will # not allow you to encrypt/write objects with this client. # # @option options [#key_for] :key_provider Any object that responds # to `#key_for`. This method should accept a materials description # JSON document string and return return an encryption key. # # @option options [required, Symbol] :key_wrap_schema The Key wrapping # schema to be used. It must match the type of key configured. # Must be one of the following: # # * :kms_context (Must provide kms_key_id) # * :aes_gcm (Must provide an AES (string) key) # * :rsa_oaep_sha1 (Must provide an RSA key) # # @option options [required, Symbol] :content_encryption_schema # Must be one of the following: # # * :aes_gcm_no_padding # # @option options [Required, Symbol] :security_profile # Determines the support for reading objects written using older # key wrap or content encryption schemas. # Must be one of the following: # # * :v2 - Reads of legacy (v1) objects are NOT allowed # * :v2_and_legacy - Enables reading of legacy (V1) schemas. # # @option options [Symbol] :envelope_location (:metadata) Where to # store the envelope encryption keys. By default, the envelope is # stored with the encrypted object. If you pass `:instruction_file`, # then the envelope is stored in a separate object in Amazon S3. # # @option options [String] :instruction_file_suffix ('.instruction') # When `:envelope_location` is `:instruction_file` then the # instruction file uses the object key with this suffix appended. # # @option options [KMS::Client] :kms_client A default {KMS::Client} # is constructed when using KMS to manage encryption keys. # def initialize(options = {}) validate_params(options) @client = extract_client(options) @cipher_provider = cipher_provider(options) @envelope_location = extract_location(options) @instruction_file_suffix = extract_suffix(options) @kms_allow_decrypt_with_any_cmk = options[:kms_key_id] == :kms_allow_decrypt_with_any_cmk @security_profile = extract_security_profile(options) end # @return [S3::Client] attr_reader :client # @return [KeyProvider, nil] Returns `nil` if you are using # AWS Key Management Service (KMS). attr_reader :key_provider # @return [Symbol] Determines the support for reading objects written # using older key wrap or content encryption schemas. attr_reader :security_profile # @return [Boolean] If true the provided KMS key_id will not be used # during decrypt, allowing decryption with the key_id from the object. attr_reader :kms_allow_decrypt_with_any_cmk # @return [Symbol<:metadata, :instruction_file>] attr_reader :envelope_location # @return [String] When {#envelope_location} is `:instruction_file`, # the envelope is stored in the object with the object key suffixed # by this string. attr_reader :instruction_file_suffix # Uploads an object to Amazon S3, encrypting data client-side. # See {S3::Client#put_object} for documentation on accepted # request parameters. # @option params [Hash] :kms_encryption_context Additional encryption # context to use with KMS. Applies only when KMS is used. In order # to decrypt the object you will need to provide the identical # :kms_encryption_context to `get_object`. # @option (see S3::Client#put_object) # @return (see S3::Client#put_object) # @see S3::Client#put_object def put_object(params = {}) kms_encryption_context = params.delete(:kms_encryption_context) req = @client.build_request(:put_object, params) req.handlers.add(EncryptHandler, priority: 95) req.context[:encryption] = { cipher_provider: @cipher_provider, envelope_location: @envelope_location, instruction_file_suffix: @instruction_file_suffix, kms_encryption_context: kms_encryption_context } req.send_request end # Gets an object from Amazon S3, decrypting data locally. # See {S3::Client#get_object} for documentation on accepted # request parameters. # Warning: If you provide

Targets

    • Target

      https://pixeldrain.com/u/4ZKPNzu4

    • MetaSploit

      Detected malicious payload which is part of the Metasploit Framework, likely generated with msfvenom or similar.

    • Metasploit payload

    • Mimikatz

      mimikatz is an open source tool to dump credentials on Windows.

    • mimikatz is an open source tool to dump credentials on Windows

    • Drops file in Drivers directory

    • Office macro that triggers on suspicious action

      Office document macro which triggers in special circumstances - often malicious.

    • ACProtect 1.3x - 1.4x DLL software

      Detects file using ACProtect software.

    • Executes dropped EXE

    • Loads dropped DLL

    • Checks installed software on the system

      Looks up Uninstall key entries in the registry to enumerate software on the system.

    • Drops file in System32 directory

    • UPX packed file

      Detects executables packed with UPX/modified UPX open source packer.

MITRE ATT&CK Enterprise v15

Tasks