Windows NT Allows Programmatic Additions
To The Administrators Group

Reported July 4, 1997 by Konstantin Sobolev

Systems Affected

Windows NT 4.0, Server and Workstation

The Problem

A newly released program (getadmin.exe) originating from Russia demonstrates an ability to add users to the Administrators group.

The program, developed by Konstantin Sobolev, runs in a command window and adds the specified user account to the Administrators group. No special permissions are required to execute the program - which also works through a telnet session.

So far, we"ve determined in-house that the program works on a Primary Domain Controller (PDC), and will add local domain accounts to the Administrators group.

This utility also works well against domain accounts. We were able to add users from a another domain into the Administrators group of the local machine.

We tested the program using getadmin username and getadmin DOMAIN-NAME\username. Both of these variations in command syntax worked, which could indicate several other configurations where this program might also work.

Here"s a log dump from the Registry Monitor (REGMON) showing what Registry keys are accessed during execution of getadmin.exe:

21 lsass.exe OpenKey 0xE1237D40\Policy SUCCESS Key: 0xE18995C0
22 lsass.exe OpenKey 0xE1237D40\Policy\SecDesc SUCCESS Key: 0xE16C9E60
23 lsass.exe QueryValue 0xE1237D40\Policy\SecDesc BUFOVRFLOW
24 lsass.exe CloseKey 0xE1237D40\Policy\SecDesc SUCCESS Key: 25E16C9E60
26 lsass.exe OpenKey 0xE1237D40\Policy\SecDesc SUCCESS Key: 0xE16C9E60
27 lsass.exe QueryValue 0xE1237D40\Policy\SecDesc SUCCESS NONE
28 lsass.exe QueryValue 0xE1237D40\Policy\SecDesc SUCCESS NONE
29 lsass.exe CloseKey 0xE1237D40\Policy\SecDesc SUCCESS Key: 0xE16C9E60
30 lsass.exe CloseKey 0xE1237D40\Policy SUCCESS Key: 0xE18995C0
31 winlogon.exe OpenKey 0xE12232C0\SOFTWARE\AntiShut\Account name SUCCESS Key: 0xE1302420
32 winlogon.exe QueryValue 0xE12232C0\SOFTWARE\AntiShut\Account name SUCCESS NTSHOP\TESTACCOUNT
33 winlogon.exe CloseKey 0xE12232C0\SOFTWARE\AntiShut\Account name SUCCESS Key: 0xE1302420
34 lsass.exe OpenKey 0xE1237D40\Policy SUCCESS Key: 0xE1302420
35 lsass.exe OpenKey 0xE1237D40\Policy\SecDesc SUCCESS Key: 0xE18995C0
36 lsass.exe QueryValue 0xE1237D40\Policy\SecDesc BUFOVRFLOW
37 lsass.exe CloseKey 0xE1237D40\Policy\SecDesc SUCCESS Key: 0xE18995C0
38 lsass.exe OpenKey 0xE1237D40\Policy\SecDesc SUCCESS Key: 0xE18995C0
39 lsass.exe QueryValue 0xE1237D40\Policy\SecDesc SUCCESS NONE
40 lsass.exe QueryValue 0xE1237D40\Policy\SecDesc SUCCESS NONE
41 lsass.exe CloseKey 0xE1237D40\Policy\SecDesc SUCCESS Key: 0xE18995C0
42 lsass.exe OpenKey 0xE1237D40\Policy SUCCESS Key: 0xE18995C0
43 lsass.exe OpenKey 0xE1237D40\Policy\SecDesc SUCCESS Key: 0xE16C9E60
44 lsass.exe QueryValue 0xE1237D40\Policy\SecDesc BUFOVRFLOW
45 lsass.exe CloseKey 0xE1237D40\Policy\SecDesc SUCCESS Key: 0xE16C9E60
46 lsass.exe OpenKey 0xE1237D40\Policy\SecDesc SUCCESS Key: 0xE16C9E60
47 lsass.exe QueryValue 0xE1237D40\Policy\SecDesc SUCCESS NONE
48 lsass.exe QueryValue 0xE1237D40\Policy\SecDesc SUCCESS NONE
49 lsass.exe CloseKey 0xE1237D40\Policy\SecDesc SUCCESS Key: 0xE16C9E60

We are stilling conducts tests to see what combinations of domains/accounts can be compromised. Feel free to contribute what you find out personally. Stay tuned for further updates.

Thomas Lopatic offered up the following analysis on GetAdmin:

I thought I"d share my findings with the net community. Hopefully someone will be able to fill in the gaps so that together we"ll get the whole picture of what GetAdmin really does.

* The hole: the system service NtAddAtom does not pay attention where it stores the result it returns. GetAdmin abuses this to set bit 0 of the byte at address NtGlobalFlag + 2. GetAdmin is traversing the list of exports in NTOSKRNL.EXE until it hits the "NtGlobalFlag" entry. However, a slightly modified version of the exploit could contain the hard coded address of NtGlobalFlag. This would make any access to NTOSKRNL.EXE unnecessary, but it would make the exploit "less portable" at the same time.

* By setting this bit, it seems, the check for debug privileges is switched off in NtOpenProcess and NtOpenThread. Thus, everyone is able to open any process currently in the system. When you open a process or a thread in Windows NT, your function call is eventually passed to the kernel services NtOpenProcess or NtOpenThread. These services verify, whether you are entitled to open the corresponding process or thread object. It seems, that the debug privilege enables you to open processes or threads not owned by you. When having a closer look at the kernel services, you notice that the above mentioned flag overrides the debug privilege, i.e. you do not need debug privileges if the above flag is set. Seems to be some kind of global debug privilege. But then again, maybe it"s more than that and I just haven"t looked closely enough. :) Could anyone from MS elaborate on this, please?

* GetAdmin opens the Winlogon process and adds a suspended thread to it. After that, it does some fiddling with the stack of the newly created thread. Guess it inserts some code and a bogus return address to make calls to GASYS.DLL, which eventually grants the administrator privileges after the thread is resumed. \[Opening processes\] is easy to verify with PView. Start PView and double click on the Winlogon process - you won"t be shown its memory statistics. Now manually set this flag, e.g. with SoftIce, and re-run PView. Now you"ll be able to look at the statistics. That means that PView is able to open the process, doesn"t it? Maybe I am missing something here.

* The Nt* functions are kernel services. User-land processes are not able to write to kernel memory. So, the problem is that NtAddAtom does not check the arguments it is passed thoroughly enough. Some background: The Nt* functions are invoked via INT 2E. EAX contains the service number (for NtAddAtom this is 3) and EDX contains a pointer to the stack frame to be used when calling NtAddAtom, i.e. the arguments, to be passed to it. NtAddAtom takes two arguments: the string representing the atom and a pointer to the memory location the result, i.e. the atom handle, is to be stored in. NtAddAtom fails to assure that this location lies within the address space of the process. Hence it is possible to have the kernel service write the atom handle anywhere we want, e.g. somewhere near NtGlobalFlag. If other services are equally sloppy, then I am afraid that this has just been the beginning in a series of bugs (the buffer overflows on Unix come to mind).

* The...correct fix is to modify the kernel so that it cannot be tricked into abusing its privileges (SUID PROGRAMS ON UNIX COME TO MIND HERE).

The author of GetAdmin, Konstantin Sobolev, has informed us here at NTSecurity.NET that the following code makes up the exploit:

ChangeNtGlobalFlag(GetNtGlobalFlagPtr());

The above code creates the exploit. The GetNtGlobalFlagPtr() can be replaced with a fix pointer, eliminating the need for READ access to the ntoskrnl.exe, making it much tougher to defend against, while at the same time, making it far less portable across NT systems.

The bug is that the subfunction in NtAddAtom does not check the address of the output . So it"s possible to write to any space of the kernel memory. Of course it is not necessary to inject a .dll into winlogon, instead, to get admin rights you can simply patch the same place of ntoskrnl.exe, or replace the process token and etc.

HERE IS THE EXECUTABLE AND SOURCE CODE

Costin Raiu points out that a similar code structure can be used to completely crash an NT system - as seen in a similar program, NTCrash. The sample code is provided below along with Costin"s message:

Here"s a small program able to crash a WindowsNT machine using the bug in NtAddAtom. Just a variation of NTCRASH.

However I have one question: why does getadmin open ntoskrnl.exe to find the address of NtAddAtom ? Using EAX=3/INT2F is portable and does not require any +r access to ntoskrnl.exe

NOTE: The location of memory overwritten by the kernel is stored in the a array. In this exploit the kernel does a write operation to FFFFFFFF - instant crash. (at least on my machine)

BTW: This program is for academic and learning purposes. No criminal intention at all.

                              ---------------------------------------------------
/* A program to bring the BSOD using the bug in NtAddAtom. Works with SP3. Author: Costin RAIU, Compile with VC++ */ void *a\[2\]; void main(void)\{      int i;      for (i=0;i

Preventing the Attack

Load the HOTFIX. And be sure to read the README file and KB article as well.

WARNING: A new variation of this same getadmin exploit still works even after installing the hotfix! Constin Raiu again offers some valuable insight below:

The most interesting function found is eax=4346. The handler of this function is located in win32k.sys By sending a carefully prepared stack to the function, you can get your code executed at ring 0 (kernel privilege. When in ring 0, my program will change the flag in NtGlobalAtom. Note that the program does not rely on NtGlobalAtom and debug privileges. I can write a small routine which patches more of the kernel, to get admin rights. However, I choosed this approach in order to make it easier for everyone: run crash4.exe, then run getadmin.exe.

Observations: The retf instruction at a0020b87 (in win32k.sys) will pop from the stack the bogus address and jump into user code. To get out from kernel mode, an iret is performed.

To get administrator rights on a hotfixed machine, run crash4.exe then run getadmin.exe.

My exploit program code follows (download the crash4.exe here):

                              /*                              Running ring 0 code.                              Author: Costin RAIU                               #include standard_disclaimer                              ****** NOTICE:                              COMPILE THIS WITH BORLAND C 5.0 ONLY!!! DOES NOT WORK WITH VC++!!!                              ******                              */                              void* a\[2\];                              void main(void) \{                                int i;                                 for (i=0;i                               

Microsoft"s Response:

It was reported that Microsoft had been informed of this issue on June 30, 1997. They released a fix on July 8, 1997 at about 3:45pm PST, BUT AS YOU CAN SEE - IT DOESN"T COMPLETELY WORK.

After a whopping 7 weeks, yet another HOTFIX was finally released that purportedly fixes this problem for good. We"ll have to wait and see about that...

If we may so bold as to make a statement to the MS security folks:

PLEASE be more thorough in your investigations - lightening quick, but thorough. More exploits are on the way if you don"t cover all the bases now!

To learn more about new NT security concerns, subscribe to NTSD.

Credit:
Reported by Konstantin Sobolev
Posted here at NTSecurity.Net July 4, 1997 11pm