1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-04-18 07:11:12 +02:00

Allow for backwards-compatible decryption

This commit is contained in:
sjanusz-r7 2023-10-24 11:52:40 +01:00
parent 62c599b2ff
commit 1a17ffc65b

@ -3,37 +3,42 @@ require 'openssl'
module MetasploitPayloads module MetasploitPayloads
module Crypto module Crypto
CIPHERS = { CIPHERS = {
chacha20: { 1 => {
name: 'chacha20'.b, name: 'chacha20'.b,
version: 1, version: { iv: 1, key: 1 },
iv: { ivs: {
value: "\x52\x25\xd7\xab\x52\x8f\x3f\xf8\x94\x97\x08\x42\x33\xb9\xd3\xb6".b, # 16 bytes 1 => {
version: 1 value: "\x52\x25\xd7\xab\x52\x8f\x3f\xf8\x94\x97\x08\x42\x33\xb9\xd3\xb6".b # 16 bytes
},
key: {
value: "\x28\x39\x97\x4c\x95\x11\x9d\x42\x6c\x8b\xff\x43\x3e\x5d\x3c\x33\x1b\x95\xd3\xea\xeb\xc9\xae\x71\x0a\x36\xe7\x98\x3d\x9d\x09\x52".b, # 32 bytes
version: 1
} }
}, },
aes_256_cbc: { keys: {
name: 'aes-256-cbc'.b, 1 => {
version: 2, value: "\x28\x39\x97\x4c\x95\x11\x9d\x42\x6c\x8b\xff\x43\x3e\x5d\x3c\x33\x1b\x95\xd3\xea\xeb\xc9\xae\x71\x0a\x36\xe7\x98\x3d\x9d\x09\x52".b, # 32 bytes
iv: { }
value: "\x3c\x09\x85\x95\x19\x09\x10\xff\x76\xf0\x48\xf7\x21\x1a\x5c\x59".b, # 16 bytes }
version: 1
}, },
key: { 2 => {
name: 'aes-256-cbc'.b,
version: { iv: 1, key: 1 },
ivs: {
1 => {
value: "\x3c\x09\x85\x95\x19\x09\x10\xff\x76\xf0\x48\xf7\x21\x1a\x5c\x59".b, # 16 bytes
}
},
keys: {
1 => {
value: "\x01\x93\x90\xfb\x84\xcd\x70\x16\x90\x1d\xc6\xf4\xf2\xfd\xcf\x59\xc4\x9c\x26\x35\x29\x67\x8c\x2d\x17\xb9\x35\xcb\x7d\xb0\x88\x7a".b, # 32 bytes value: "\x01\x93\x90\xfb\x84\xcd\x70\x16\x90\x1d\xc6\xf4\xf2\xfd\xcf\x59\xc4\x9c\x26\x35\x29\x67\x8c\x2d\x17\xb9\x35\xcb\x7d\xb0\x88\x7a".b, # 32 bytes
version: 1 }
} }
} }
}.freeze }.freeze
CURRENT_CIPHER = CIPHERS[:aes_256_cbc] CIPHER_VERSION = 2
CIPHER_VERSION = CURRENT_CIPHER[:version] CURRENT_CIPHER = CIPHERS[CIPHER_VERSION]
KEY_VERSION = CURRENT_CIPHER[:key][:version] KEY_VERSION = CURRENT_CIPHER[:version][:key]
IV_VERSION = CURRENT_CIPHER[:iv][:version] IV_VERSION = CURRENT_CIPHER[:version][:iv]
# Binary String, unsigned char, unsigned char, unsigned char # Binary String, unsigned char, unsigned char, unsigned char
ENCRYPTED_PAYLOAD_HEADER = ['msf', CIPHER_VERSION, IV_VERSION, KEY_VERSION].pack('A*CCC') ENCRYPTED_PAYLOAD_HEADER = ['msf', CIPHER_VERSION, IV_VERSION, KEY_VERSION].pack('A*CCC').freeze
private_constant :CIPHERS private_constant :CIPHERS
private_constant :CURRENT_CIPHER private_constant :CURRENT_CIPHER
@ -47,8 +52,8 @@ module MetasploitPayloads
cipher = ::OpenSSL::Cipher.new(CURRENT_CIPHER[:name]) cipher = ::OpenSSL::Cipher.new(CURRENT_CIPHER[:name])
cipher.encrypt cipher.encrypt
cipher.iv = CURRENT_CIPHER[:iv][:value] cipher.iv = CURRENT_CIPHER[:ivs][IV_VERSION][:value]
cipher.key = CURRENT_CIPHER[:key][:value] cipher.key = CURRENT_CIPHER[:keys][KEY_VERSION][:value]
output = ENCRYPTED_PAYLOAD_HEADER.dup output = ENCRYPTED_PAYLOAD_HEADER.dup
output << cipher.update(plaintext) output << cipher.update(plaintext)
@ -60,11 +65,17 @@ module MetasploitPayloads
def self.decrypt(ciphertext: '') def self.decrypt(ciphertext: '')
raise ::ArgumentError, 'Unable to decrypt ciphertext: ' << ciphertext, caller unless ciphertext.to_s raise ::ArgumentError, 'Unable to decrypt ciphertext: ' << ciphertext, caller unless ciphertext.to_s
cipher = ::OpenSSL::Cipher.new(CURRENT_CIPHER[:name]) # Use the correct algorithm based on the version in the header
_msf_header, cipher_version, iv_version, key_version = ciphertext.unpack('A3CCC')
current_cipher = CIPHERS[cipher_version]
cipher = ::OpenSSL::Cipher.new(current_cipher[:name])
iv = current_cipher[:ivs][iv_version][:value]
key = current_cipher[:keys][key_version][:value]
cipher.decrypt cipher.decrypt
cipher.iv = CURRENT_CIPHER[:iv][:value] cipher.iv = iv
cipher.key = CURRENT_CIPHER[:key][:value] cipher.key = key
# Remove encrypted header if present # Remove encrypted header if present
ciphertext = ciphertext.sub(ENCRYPTED_PAYLOAD_HEADER, '') ciphertext = ciphertext.sub(ENCRYPTED_PAYLOAD_HEADER, '')