1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-02-16 00:24:29 +01:00

Add generation & reading of encrypted payloads

This commit is contained in:
sjanusz-r7 2023-10-09 15:29:22 +01:00
parent b145c82fb1
commit 5520fec2a4
2 changed files with 54 additions and 8 deletions

View File

@ -46,13 +46,28 @@ platform_config = {
}
}
def chacha20_encrypt(contents: '')
cipher = ::OpenSSL::Cipher.new('chacha20')
cipher.encrypt
cipher.iv = 'EncryptedPayload'
cipher.key = 'Rapid7MetasploitEncryptedPayload'
encrypted_contents = 'encrypted_payload_chacha20_v1'
encrypted_contents << cipher.update(contents)
encrypted_contents << cipher.final
encrypted_contents
end
def copy_files(cnf, meterpreter_dest)
cnf[:sources].each do |f|
cnf[:extensions].each do |ext|
Dir.glob("#{f}/*.#{ext}").each do |bin|
target = File.join(meterpreter_dest, File.basename(bin))
print("Copying: #{bin} -> #{target}\n")
FileUtils.cp(bin, target)
contents = ::File.binread(::File.expand_path(bin))
encrypted_contents = chacha20_encrypt(contents: contents)
::File.binwrite(::File.expand_path(target), encrypted_contents)
end
end
end

View File

@ -12,6 +12,10 @@ module MetasploitPayloads
METERPRETER_SUBFOLDER = 'meterpreter'
USER_DATA_SUBFOLDER = 'payloads'
ENCRYPTED_PAYLOAD_HEADER = 'encrypted_payload_chacha20_v1'
CHACHA20_IV = 'EncryptedPayload' # 16 bytes
CHACHA20_KEY = 'Rapid7MetasploitEncryptedPayload' # 32 bytes
#
# @return [Array<Hash<String, Symbol>>] An array of filenames with warnings. Provides a file name and error.
# Empty if all needed Meterpreter files exist and have the correct hash.
@ -43,12 +47,13 @@ module MetasploitPayloads
manifest_contents.each_line do |line|
filename, hash_type, hash = line.chomp.split(':')
begin
filename = filename.sub('./data/', '')
# self.path prepends the gem data directory, which is already present in the manifest file.
out_path = self.path(filename.sub('./data/', ''))
out_path = self.path(filename)
# self.path can return a path to the gem data, or user's local data.
bundled_file = out_path.start_with?(data_directory)
if bundled_file
file_hash_match = (::OpenSSL::Digest.new(hash_type, ::File.binread(out_path)).to_s == hash)
file_hash_match = (::OpenSSL::Digest.new(hash_type, self.read(filename)).to_s == hash)
unless file_hash_match
e = ::MetasploitPayloads::HashMismatchError.new(out_path)
manifest_errors.append({ path: e.path, error: e })
@ -137,15 +142,41 @@ module MetasploitPayloads
#
# Get the contents of any file packaged in this gem by local path and name.
# If the file is encrypted using ChaCha20, automatically decrypt it and return the file contents.
#
def self.read(*path_parts)
file_path = path(path_parts)
if file_path.nil?
full_path = ::File.join(path_parts)
raise ::MetasploitPayloads::NotFoundError, full_path, caller
file_path = self.path(path_parts)
begin
file_contents = ::File.binread(file_path)
rescue ::Errno::ENOENT => _e
raise ::MetasploitPayloads::NotFoundError, file_path, caller
rescue ::Errno::EACCES => _e
raise ::MetasploitPayloads::NotReadableError, file_path, caller
rescue ::StandardError => e
raise e
end
::File.binread(file_path)
encrypted_file = file_contents.start_with?(ENCRYPTED_PAYLOAD_HEADER)
return file_contents unless encrypted_file
self.decrypt_payload(payload: file_contents)
end
def self.decrypt_payload(payload: '')
return payload unless payload.start_with?(ENCRYPTED_PAYLOAD_HEADER)
# Remove the header from the file.
encrypted_contents = payload.sub(ENCRYPTED_PAYLOAD_HEADER, '')
cipher = ::OpenSSL::Cipher.new('chacha20')
cipher.decrypt # Call before using .key
cipher.iv = CHACHA20_IV
cipher.key = CHACHA20_KEY
decrypted_contents = cipher.update(encrypted_contents)
decrypted_contents << cipher.final
decrypted_contents
end
#