1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-01-02 11:36:22 +01:00

Move encryption/decryption into a separate Crypto module

This commit is contained in:
sjanusz-r7 2023-10-12 14:33:32 +01:00
parent e1f8da57e4
commit 93d467cd4a
4 changed files with 71 additions and 36 deletions

View File

@ -1,5 +1,6 @@
require "bundler/gem_tasks"
require 'openssl'
require 'metasploit-payloads/crypto'
c_source = "../c/meterpreter/"
java_source = "../java"
@ -46,19 +47,6 @@ 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|
@ -66,7 +54,7 @@ def copy_files(cnf, meterpreter_dest)
target = File.join(meterpreter_dest, File.basename(bin))
print("Copying: #{bin} -> #{target}\n")
contents = ::File.binread(::File.expand_path(bin))
encrypted_contents = chacha20_encrypt(contents: contents)
encrypted_contents = ::MetasploitPayloads::Crypto.encrypt(plaintext: contents)
::File.binwrite(::File.expand_path(target), encrypted_contents)
end
end

View File

@ -3,6 +3,7 @@
require 'openssl' unless defined? OpenSSL::Digest
require 'metasploit-payloads/version' unless defined? MetasploitPayloads::VERSION
require 'metasploit-payloads/error' unless defined? MetasploitPayloads::Error
require 'metasploit-payloads/crypto' unless defined? MetasploitPayloads::Crypto
#
# This module dispenses Metasploit payload binary files
@ -12,10 +13,6 @@ 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.
@ -157,26 +154,10 @@ module MetasploitPayloads
raise e
end
encrypted_file = file_contents.start_with?(ENCRYPTED_PAYLOAD_HEADER)
encrypted_file = file_contents.start_with?(Crypto::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
Crypto.decrypt(ciphertext: file_contents)
end
#

View File

@ -0,0 +1,44 @@
require 'openssl'
module MetasploitPayloads
module Crypto
CIPHER_NAME = 'chacha20'.freeze
IV = 'EncryptedPayload'.freeze # 16 bytes
KEY = 'Rapid7MetasploitEncryptedPayload'.freeze # 32 bytes
ENCRYPTED_PAYLOAD_HEADER = 'encrypted_payload_chacha20_v1'.freeze
def self.encrypt(plaintext: '')
raise ::ArgumentError, 'Unable to encrypt plaintext: ' << plaintext, caller unless plaintext.to_s
cipher = ::OpenSSL::Cipher.new(CIPHER_NAME)
cipher.encrypt
cipher.iv = IV
cipher.key = KEY
output = ENCRYPTED_PAYLOAD_HEADER.dup
output << cipher.update(plaintext)
output << cipher.final
output
end
def self.decrypt(ciphertext: '')
raise ::ArgumentError, 'Unable to decrypt ciphertext: ' << ciphertext, caller unless ciphertext.to_s
cipher = ::OpenSSL::Cipher.new(CIPHER_NAME)
cipher.decrypt
cipher.iv = IV
cipher.key = KEY
# Remove encrypted header if present
ciphertext = ciphertext.sub(ENCRYPTED_PAYLOAD_HEADER, '')
output = cipher.update(ciphertext)
output << cipher.final
output
end
end
end

View File

@ -0,0 +1,22 @@
require 'spec_helper'
require 'metasploit-payloads'
RSpec.describe ::MetasploitPayloads::Crypto do
describe '#encrypt' do
let(:encrypted_header) { "encrypted_payload_chacha20_v1".b }
let(:plaintext) { "Hello World!".b }
let(:ciphertext) { encrypted_header + "\\c\xB6N\x95\xE58\x8D\xDF\xBF4c".b }
it 'can encrypt plaintext' do
expect(described_class.encrypt(plaintext: plaintext)).to eq ciphertext
end
it 'can decrypt ciphertext' do
expect(described_class.decrypt(ciphertext: ciphertext)).to eq plaintext
end
it 'is idempotent' do
expect(described_class.decrypt(ciphertext: described_class.encrypt(plaintext: plaintext))).to eq plaintext
end
end
end