A wonderful kernel exploit

Source: Internet
Author: User

A serious security vulnerability has recently emerged in Linux kernel. Non-root users can obtain root permissions through the exploit Vulnerability. This is not uncommon. It is worth mentioning that this patch seems so common that most of us will not think this is a security issue. Let's take a look at the patch for this issue, which is the following:

  static int perf_swevent_init(struct perf_event *event) {- int event_id = event->attr.config;+ u64 event_id = event->attr.config;  if (event->attr.type != PERF_TYPE_SOFTWARE)  return -ENOENT;

 

At first glance, we felt that this was probably just a small warning reported by the compiler. How could it cause such a serious security problem? In the unpatched code, event_id is a signed integer, and only the upper bound is checked in the following two lines of code:
if (event_id>= PERF_COUNT_SW_MAX)                return -ENOENT;

 

If the passed event-> attr. config value exactly sets the symbol bit, the event_id will become a negative value and will be able to escape the above check. What does a negative value mean? Continue with the code below:
if (!event->parent) {                int err;                err = swevent_hlist_get(event);                if (err)                        return err;                atomic_inc(&perf_swevent_enabled[event_id]);                event->destroy = sw_perf_event_destroy;        }

 

This indicates that the array is out of bounds! At this time, you should start to sweat. To continue, the array perf_swevent_enabled [] on RHEL6 is defined as: plain textc: atomic_t perf_swevent_enabled [disabled], while atomic_t is basically an int, that is, perf_swevent_enabled [] is an integer array, when you use event_id to access the array, the value of event_id is multiplied by 4 and the starting address of the array is added. Easy! Okay, via System. in the map file, we can get the address of perf_swevent_enabled: ffffff81f360c0 B perf_swevent_enabled. When the event-> attr. when config = 0 xffffffff (I .e.-1), on x86_64, we will eventually get: 0 records * 4 + 0xffffffff81f360c0 = 0xffffff81f360bc, similarly when event-> attr. when config = 0 xfffffffe, we get: 0 xfffffffffffffffe * 4 + 0xffffffffff81f360c0 = 0xFFFFFFFF81F360B8. Therefore, the above-mentioned atomic_inc () actually adds the values stored in the previous, both addresses point to the kernel space (see Documentation/ X86/x86_64/mm.txt )! At this time, you should feel nervous... More interesting things will happen in the sw_perf_event_destroy () function. It is called when the fd returned by perf_event_open () is disabled. The RHEL6 is defined as follows:
static void sw_perf_event_destroy(struct perf_event *event){        u64 event_id = event->attr.config;        WARN_ON(event->parent);        atomic_dec(&perf_swevent_enabled[event_id]);        swevent_hlist_put(event);}

 

Obviously, event_id is of the unsigned type this time. So, same as above, when event-> attr. when config = 0 xffffffff, we get: 0 xffffffffff * 4 + 0xffffffff81f360c0 = 0x0000000381F360BC when event-> attr. when config = 0 xfffffffe, we get: 0 xfffffffe * 4 + 0xffffffff81f360c0 = 0x0000000381F360B8. So the atomic_dec () here actually reduces the value in the user space address. The above is "Basic Knowledge". With this knowledge, we can see what exploit code has done. The code snippets are as follows:
#define BASE  0x380000000#define SIZE  0x010000000  assert((map = mmap((void*)BASE, SIZE, 3, 0x32, 0,0)) == (void*)BASE);  memset(map, 0, SIZE);  sheep(-1); sheep(-2);    // sheep will just invoke perf_event_open                           // syscall with attr.config set to the param  for (i = 0; i <SIZE/4; i++) if (map[i]) {    assert(map[i+1]);    break;  }

 

It first sets the starting address of mmap () to a memory area of 0x380000000. Then, perf_event_open () is called twice with attr. config as-1 and-2 respectively (). According to the previous calculation, it actually adds the memory values at 0xFFFFFFFF81F360BC and 0xFFFFFFFF81F360B8 respectively, reducing the values of 0x0000000381F360BC and 0x0000000381F360B8. The for loop is to find the address of the memory to be reduced, so that the address of the perf_swevent_enabled [] array can be calculated (System. map does not always exist. If it exists and is readable, we can directly read this value ). With this address, we can manipulate the 32bit value somewhere in the kernel and add one to the value. Because of this, the author cleverly chooses the Interrupt Descriptor Table-an array of 16-byte descriptors, and its address can be obtained through the sidt command. Its descriptor structure is defined as follows: Offset Size Description0 2 Offset low bits (0 .. 15) 2 2 Selector (Code segment selector) 4 1 Zero5 1 Type and Attributes (same as before) 6 2 Offset middle bits (16 .. 31) 8 4 Offset high bits (32 .. 63) 12 4 Zero the most interesting thing here is that the offset is 8, and the value of x86_64 is 0 xffffffff. The Interrupt Descriptor selected by the author is 0x4, so its offset relative to the Interrupt Descriptor Table is actually 0x48. The current task is to use perf_swevent_enabled [] to calculate the memory address with an offset of 8 in the Interrupt Descriptor and add one to it! The following code is used to do this: sheep (-I + (idt. addr & 0 xffffffff)-0x80000000)/4) + 16); I is an offset of perf_swevent_enabled [] Found in the for loop, idt. addr is the absolute kernel address of the Interrupt Descriptor Table. take its low 32-bit value and subtract 0x80000000 to get the low 28-bit value as the offset. Divide by 4 because the array is int, the last 16 is the offset in the 0x4 Interrupt Descriptor (4 has been removed), so the parameters in sheep () are the expected offset, in this case, the kernel adds 1 to the 0 xffffffff offset of 8 in the 0x4 Interrupt Descriptor, which becomes 0 and the address of the user space! So the subsequent int 0x4 will actually jump to the Code already set in the user space !!! However, this code is quite cool, but it means to change the uid/gid of the current process to 0 to improve the permission, so you finally get a shell with the root permission! Attack success! Note: The above link may not be available. The exploit code can also be seen here: https://gist.github.com/onemouth/5625174


Original article: http://www.kuqin.com/linux/20130710/334644.html
 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.