This presentation covers utilizing VMwares (GDB) debugging protocol to invasive inject commands into a Linux-x64 target. Automatic detection of kernel API is performed to locate _vmalloc & call_usermodehelper* functions across all 3x and 4x kernels.
Compromising Linux Virtual Machines with Debugging Mechanisms
1. Compromising Linux Virtual Machines
with Debugging Mechanisms
Russell Sanford
xort@blacksecurity.org
October 2016
2. What are we going to be covering?
• Some kernel hacking!
• Injecting API calls into running 64bit kernels
• All Kernels 3x/4x (64bit)
• Tool Release automating attack: bl4ck_vmpop.py !!!
3. Why?
• Bypass disk encryption schemes
• Get to underlining OS & code to audit!
• Nobody has talked about abusing VMware’s debugging features?
Previous work has only be done on infecting paused VM memory stored on disk (SLOW!!!)
4. Tools Involved
• IDA Pro 64bit
• VMware Workstation >= 5.0 or VMware Player >= 3.0
• Binwalk
5. The Old Way – Manual Exploitation
• Compiling another kernel of the same version
• Comparing function calls & string usage against the
kernel with symbols.
• Slowly locating and labelling the functions needed
Manually hooking function calls and Injecting substituted
commands into target
6. VMware GDB Stubs
•VMware Workstation >= 5.0
•VMware Player >= 3.0
•Fusion
•Allow R/W/X of memory, ability to single step, etc @ kernel level
•Can be done to booted machine (must be temporarily paused)
•When attaching to VMware we land in default_idle()
7. The Plan… Automating Exploitation
•1) Extracting the kernel for IDA with binwalk
•2) Decompile kernel in IDA
•3) Enable debugging in VMware VMX file
•4) Attach IDA database to VMware’s gdbserver port (8864)
•5) Locate kernel API using unique byte sequences *
• A) _vmalloc()
• B) call_usermodehelper_setup()
• C) call_usermodehelper_exec()
• D) call_usermodehelper_fns()
•6) Back up current state of processor (Back up Registers)
•7) Call _vmalloc() to allocate working space for passing argv[] (program arguments)
•8) Populate memory area with argv[] information
•9) Call call_usermodehelper_setup() to initialize subprocess_info structure *
•10) Pass subprocess_info structure to call_usermodehelper_exec() *
•11) Restore backed up registers and restore control to CPU
* In some 3x versions call_usermodehelper_fns() is used in place of _setup() + _exec()
8. Kernel API Involved
_vmalloc(unsigned __int64 size,
gfp_t gfp_mask,
pgprot_t prot )
call_usermodehelper_setup(char *path,
char **argv,
char **envp,
gfp_t gfp_mask,
int (*init)(subprocess_info *, cred *),
void (*cleanup)(subprocess_info *),
void *data )
call_usermodehelper_fns(char *path,
char **argv,
char **envp,
int wait,
int (*init)(subprocess_info *, cred *),
void (*cleanup)(subprocess_info *),
void *data )
call_usermodehelper_exec(subprocess_info *sub_info,
int wait )
1) Allocating Memory
_vmalloc()
2) Launching a Command In Userland
call_usermodehelper_setup()
call_usermodehelper_exec()
OR
call_usermodehelper_fns()
10. Step #1 Extracting the kernel with binwalk for IDA
binwalk –e my_kernel.bin)
cd _my_kernel.bin
file * | grep ELF
A directory named “_my_kernel.bin” will be created
Change into the directory of extracted files
use the ‘file’ and ‘grep’ commands to locate extracted
kernel
11. Step #3 Enable debugging in VMware VMX file
•Virtual Machines Can Be Paused and Restarted in Debug Mode !
(gdbserver)
12. Step #2 Decompile the Kernel in IDA
1) Open the 64-bit ELF file with IDA Pro
and click “OK” to begin analysis
2) Wait for analysis to complete. Analysis
indicator at bottom right to say ‘idle’
13. Step #4 Attach IDA database to VMware’s gdbserver
Select Debugger->Select Debugger
from drop down menu and Select
‘Remote GDB debugger’
Select Debugger->Process Options
and verify port 8864 is selected
Select Debugger->Attach To
Process to connect to Vmware’s
gdbserver.
14. Step #4 Attach IDA database to VMware’s gdbserver
Select Debugger->Debugger
Options from drop down menu
Click ‘Set Specific Options’ in the Debugger Setup Window
Click ‘Memory Map’ in the GDB Configuration Window
Right-Click in the ‘Manual Memory Regions’ Window and select ‘Insert’
Continued….
15. Step #4 Attach IDA database to VMware’s gdbserver
The default End Address is
0xFF00000000000000
Change this value to
0xFFFFFFFFFFFFF000
…Continued
16. Step #5 Locate kernel API using unique byte sequences
Formula:
• When ‘Search Key‘ is encountered in memory – Analyze the next X bytes
(predetermined range)
• Check byte range for patterns known to exist uniquely to the function we are
looking for
• Check byte range to make sure patterns do not exist within range
• Find beginning of function
17. Step #6 Back up current state of processor
•Back up current state of processor (Back up Registers)
•Easy to do with IDA
•Backup up Registers with IDA Pro’s GetRegValue() function
18. Step #7 Allocating working space with _vmalloc()
• vmalloc() > kmalloc() for our needs
•Provides Larger Non-Contiguous Memory Allocations
_vmalloc(unsigned __int64 size, gfp_t gfp_mask,
pgprot_t prot)
_vmalloc(0x1000, 0x20, 0x8000000000000163)
19. Step #8 Populate memory area with argv[] info
• Top area is set aside to hold Qword (8 bytes)
pointers to strings (ARGV array)
• Ends with a NULL (0x0) Qword to terminate
array
• Bottom area will hold actual string data.
• Strings are C-Strings (NULL byte terminated)
20. Step #9 Call call_usermodehelper_setup() to
initialize subprocess_info struct
Call_usermodehelper_setup()
returns a pointer to a
initialized subprocess_info
structure.
ENVP, *init, *cleanup, and *data
Can be NULL
call_usermodehelper_setup(char *path, char **argv, char **envp, gfp_t gfp_mask,
int (*init)(subprocess_info *, cred *), void (*cleanup)(subprocess_info *), void *data)
21. Step #10 Pass subprocess_info structure to
call_usermodehelper_exec()
• Pass subprocess_info structure to call_usermodehelper_exec()
• Call with wait = 0
• Executes command in User Land
call_usermodehelper_exec(subprocess_info *sub_info, int wait)
22. Step #11 Restore processor’s saved state
•Restore the saved state of processor (Back up Registers)
•Easy to do with IDA
•Restore Registers with SetRegValue() function