Files
metasploit-gs/lib/msf/base/sessions/encrypted_shell.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

114 lines
2.7 KiB
Ruby
Raw Normal View History

2019-07-16 11:31:10 -05:00
# -*- coding: binary -*-
2019-10-28 16:25:28 -05:00
require 'securerandom'
2019-07-15 12:16:33 -05:00
module Msf
module Sessions
2019-07-16 11:31:10 -05:00
class EncryptedShell < Msf::Sessions::CommandShell
include Msf::Session::Basic
include Msf::Session::Provider::SingleCommandShell
2019-11-18 13:41:01 -06:00
include Msf::Payload::Windows::PayloadDBConf
2019-07-15 12:16:33 -05:00
attr_accessor :arch
attr_accessor :platform
2019-09-30 15:05:07 -05:00
attr_accessor :iv
attr_accessor :key
attr_accessor :staged
2019-07-15 12:16:33 -05:00
2019-11-20 11:24:23 -06:00
attr_accessor :chacha_cipher
2019-10-10 12:14:11 -05:00
# define some sort of method that checks for
# the existence of payload in the db before
# using datastore
2019-10-03 13:31:30 -05:00
def initialize(rstream, opts={})
2019-07-15 12:16:33 -05:00
self.arch ||= ""
2019-07-16 11:31:10 -05:00
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 bootstrap(datastore = {}, handler = nil)
@key = datastore[:key] || datastore['ChachaKey']
nonce = datastore[:nonce] || datastore['ChachaNonce']
2019-11-14 10:29:58 -06:00
@iv = nonce
2019-10-10 12:14:11 -05:00
# staged payloads retrieve UUID via
# handle_connection() in stager.rb
unless @staged
curr_uuid = rstream.get_once(16, 1)
2019-11-18 13:41:01 -06:00
@key, @nonce = retrieve_chacha_creds(curr_uuid)
2019-11-14 10:29:58 -06:00
@iv = @nonce ? @nonce : "\0" * 12
2019-10-10 12:14:11 -05:00
unless @key && @nonce
print_status('Failed to retrieve key/nonce for uuid. Resorting to datastore')
2019-10-10 12:14:11 -05:00
@key = datastore['ChachaKey']
2019-11-14 10:29:58 -06:00
@iv = datastore['ChachaNonce']
2019-10-10 12:14:11 -05:00
end
end
2019-10-03 13:31:30 -05:00
2019-10-28 16:25:28 -05:00
new_nonce = SecureRandom.hex(6)
2019-11-14 10:29:58 -06:00
new_key = SecureRandom.hex(16)
2019-11-20 11:24:23 -06:00
@chacha_cipher = Rex::Crypto::Chacha20.new(@key, @iv)
new_cipher = @chacha_cipher.chacha20_crypt(new_nonce + new_key)
2019-10-03 13:31:30 -05:00
rstream.write(new_cipher)
2019-10-07 08:44:48 -05:00
@key = new_key
2019-11-14 10:29:58 -06:00
@iv = new_nonce
2019-11-20 11:24:23 -06:00
@chacha_cipher.reset_cipher(@key, @iv)
super(datastore, handler)
2019-07-15 12:16:33 -05:00
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)
# Needed to avoid crashing the +chacha20_crypt+ method
return nil unless rv
2019-11-20 11:24:23 -06:00
decrypted = @chacha_cipher.chacha20_crypt(rv)
2019-07-15 12:16:33 -05:00
framework.events.on_session_output(self, decrypted) if decrypted
2019-11-20 11:24:23 -06:00
2019-07-16 11:31:10 -05:00
return decrypted
2019-07-15 12:16:33 -05:00
rescue ::Rex::SocketError, ::EOFError, ::IOError, ::Errno::EPIPE => e
shell_close
raise e
end
##
# Overridden from Msf::Sessions::CommandShell#shell_write
2019-11-14 10:29:58 -06:00
#
2019-07-15 12:16:33 -05:00
# Encrypt data then write it to the console
#
def shell_write(buf)
return unless buf
framework.events.on_session_command(self, buf.strip)
2019-11-20 11:24:23 -06:00
encrypted = @chacha_cipher.chacha20_crypt(buf)
2019-07-15 12:16:33 -05:00
rstream.write(encrypted)
rescue ::Rex::SocketError, ::EOFError, ::IOError, ::Errno::EPIPE => e
shell_close
raise e
end
2019-07-16 11:31:10 -05:00
end
2019-07-15 12:16:33 -05:00
end
end