metasploit-framework/lib/msf/base/sessions/encrypted_shell.rb

111 lines
2.6 KiB
Ruby

# -*- coding: binary -*-
require 'msf/base'
require 'securerandom'
module Msf
module Sessions
class EncryptedShell < Msf::Sessions::CommandShell
include Msf::Session::Basic
include Msf::Session::Provider::SingleCommandShell
include Msf::Payload::Windows::PayloadDBConf
attr_accessor :arch
attr_accessor :platform
attr_accessor :iv
attr_accessor :key
attr_accessor :staged
attr_accessor :chacha_cipher
# define some sort of method that checks for
# the existence of payload in the db before
# using datastore
def initialize(rstream, opts={})
self.arch ||= ""
self.platform = "windows"
@staged = opts[:datastore][:staged]
super
end
def type
"Encrypted"
end
def desc
"Encrypted reverse shell"
end
def self.type
self.class.type = "Encrypted"
end
def process_autoruns(datastore)
@key = datastore[:key] || datastore['ChachaKey']
nonce = datastore[:nonce] || datastore['ChachaNonce']
@iv = nonce
# staged payloads retrieve UUID via
# handle_connection() in stager.rb
unless @staged
curr_uuid = rstream.get_once(16, 1)
@key, @nonce = retrieve_chacha_creds(curr_uuid)
@iv = @nonce ? @nonce : "\0" * 12
unless @key && @nonce
print_status('Failed to retrieve key/nonce for uuid. Resorting to datastore')
@key = datastore['ChachaKey']
@iv = datastore['ChachaNonce']
end
end
new_nonce = SecureRandom.hex(6)
new_key = SecureRandom.hex(16)
@chacha_cipher = Rex::Crypto::Chacha20.new(@key, @iv)
new_cipher = @chacha_cipher.chacha20_crypt(new_nonce + new_key)
rstream.write(new_cipher)
@key = new_key
@iv = new_nonce
@chacha_cipher.reset_cipher(@key, @iv)
end
##
# Overridden from Msf::Sessions::CommandShell#shell_read
#
# Read encrypted data from console and decrypt it
#
def shell_read(length=-1, timeout=1)
rv = rstream.get_once(length, timeout)
decrypted = @chacha_cipher.chacha20_crypt(rv)
framework.events.on_session_output(self, decrypted) if decrypted
return decrypted
rescue ::Rex::SocketError, ::EOFError, ::IOError, ::Errno::EPIPE => e
shell_close
raise e
end
##
# Overridden from Msf::Sessions::CommandShell#shell_write
#
# Encrypt data then write it to the console
#
def shell_write(buf)
return unless buf
framework.events.on_session_command(self, buf.strip)
encrypted = @chacha_cipher.chacha20_crypt(buf)
rstream.write(encrypted)
rescue ::Rex::SocketError, ::EOFError, ::IOError, ::Errno::EPIPE => e
shell_close
raise e
end
end
end
end