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:
parent
e1f8da57e4
commit
93d467cd4a
16
gem/Rakefile
16
gem/Rakefile
@ -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
|
||||
|
@ -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
|
||||
|
||||
#
|
||||
|
44
gem/lib/metasploit-payloads/crypto.rb
Normal file
44
gem/lib/metasploit-payloads/crypto.rb
Normal 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
|
22
gem/spec/metasploit_payloads/crypto_spec.rb
Normal file
22
gem/spec/metasploit_payloads/crypto_spec.rb
Normal 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
|
Loading…
Reference in New Issue
Block a user