├── .gitignore ├── ClsidExplorer ├── CLSIDExplorer.sln ├── CLSIDExplorer │ ├── CLSIDExplorer.vcxproj │ ├── CLSIDExplorer.vcxproj.filters │ ├── CLSIDExplorer.vcxproj.user │ ├── Parser.cpp │ ├── Parser.h │ ├── main.cpp │ └── main.h └── x64 │ └── Debug │ ├── CLSIDExplorer.exe │ └── CLSIDExplorer.pdb ├── ComDiver ├── COMDiver.sln ├── COMDiver │ ├── COMDiver.vcxproj │ ├── COMDiver.vcxproj.filters │ ├── COMDiver.vcxproj.user │ ├── analyzer.cpp │ ├── analyzer.h │ ├── argparse.cpp │ ├── argparse.h │ ├── enumerator.cpp │ ├── enumerator.h │ ├── main.cpp │ └── main.h └── x64 │ └── Debug │ ├── ComDiver.exe │ └── ComDiver.pdb ├── ComTraveller ├── ComTraveller.sln ├── ComTraveller │ ├── ComTraveller.vcxproj │ ├── ComTraveller.vcxproj.filters │ ├── ComTraveller.vcxproj.user │ ├── enumerator.cpp │ ├── enumerator.h │ ├── main.cpp │ ├── main.h │ └── x64 │ │ └── Debug │ │ ├── ComTraveller.exe.recipe │ │ ├── ComTraveller.vcxproj.FileListAbsolute.txt │ │ └── vc143.idb └── x64 │ └── Debug │ ├── ComTraveller.exe │ ├── ComTraveller.pdb │ └── rep.csv ├── MonikerHound ├── MonikerHound.sln ├── MonikerHound │ ├── MonikerHound.vcxproj │ ├── MonikerHound.vcxproj.filters │ ├── MonikerHound.vcxproj.user │ └── Source.cpp └── x64 │ └── Debug │ ├── MonikerHound.exe │ └── MonikerHound.pdb ├── PermissionHunter └── PermissionHunter │ ├── PermissionHunter.sln │ ├── PermissionHunter │ ├── App.config │ ├── PermissionHunter.csproj │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── bin │ │ └── Debug │ │ │ ├── PermissionHunter.exe │ │ │ ├── PermissionHunter.exe.config │ │ │ ├── PermissionHunter.pdb │ │ │ └── result.xlsx │ ├── obj │ │ └── Debug │ │ │ ├── .NETFramework,Version=v4.8.AssemblyAttributes.cs │ │ │ ├── DesignTimeResolveAssemblyReferencesInput.cache │ │ │ ├── PermissionHunter.csproj.AssemblyReference.cache │ │ │ ├── PermissionHunter.csproj.CoreCompileInputs.cache │ │ │ ├── PermissionHunter.csproj.FileListAbsolute.txt │ │ │ ├── PermissionHunter.exe │ │ │ └── PermissionHunter.pdb │ └── packages.config │ └── packages │ └── Microsoft.Office.Interop.Excel.15.0.4795.1001 │ ├── .signature.p7s │ ├── Microsoft.Office.Interop.Excel.15.0.4795.1001.nupkg │ └── lib │ ├── net20 │ └── Microsoft.Office.Interop.Excel.dll │ └── netstandard2.0 │ └── Microsoft.Office.Interop.Excel.dll └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | *.csv 19 | *.pdb 20 | *pdb* 21 | 22 | 23 | # Visual Studio 2015/2017 cache/options directory 24 | .vs/ 25 | # Uncomment if you have tasks that create the project's static files in wwwroot 26 | #wwwroot/ 27 | 28 | # Visual Studio 2017 auto generated files 29 | Generated\ Files/ 30 | 31 | # MSTest test Results 32 | [Tt]est[Rr]esult*/ 33 | [Bb]uild[Ll]og.* 34 | 35 | # NUnit 36 | *.VisualState.xml 37 | TestResult.xml 38 | nunit-*.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # Benchmark Results 46 | BenchmarkDotNet.Artifacts/ 47 | 48 | # .NET Core 49 | project.lock.json 50 | project.fragment.lock.json 51 | artifacts/ 52 | 53 | # ASP.NET Scaffolding 54 | ScaffoldingReadMe.txt 55 | 56 | # StyleCop 57 | StyleCopReport.xml 58 | 59 | # Files built by Visual Studio 60 | *_i.c 61 | *_p.c 62 | *_h.h 63 | *.ilk 64 | *.meta 65 | *.obj 66 | *.iobj 67 | *.pch 68 | *.pdb 69 | *.ipdb 70 | *.pgc 71 | *.pgd 72 | *.rsp 73 | *.sbr 74 | *.tlb 75 | *.tli 76 | *.tlh 77 | *.tmp 78 | *.tmp_proj 79 | *_wpftmp.csproj 80 | *.log 81 | *.tlog 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # TeamCity is a build add-in 124 | _TeamCity* 125 | 126 | # DotCover is a Code Coverage Tool 127 | *.dotCover 128 | 129 | # AxoCover is a Code Coverage Tool 130 | .axoCover/* 131 | !.axoCover/settings.json 132 | 133 | # Coverlet is a free, cross platform Code Coverage Tool 134 | coverage*.json 135 | coverage*.xml 136 | coverage*.info 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # NuGet Symbol Packages 186 | *.snupkg 187 | # The packages folder can be ignored because of Package Restore 188 | **/[Pp]ackages/* 189 | # except build/, which is used as an MSBuild target. 190 | !**/[Pp]ackages/build/ 191 | # Uncomment if necessary however generally it will be regenerated when needed 192 | #!**/[Pp]ackages/repositories.config 193 | # NuGet v3's project.json files produces more ignorable files 194 | *.nuget.props 195 | *.nuget.targets 196 | 197 | # Microsoft Azure Build Output 198 | csx/ 199 | *.build.csdef 200 | 201 | # Microsoft Azure Emulator 202 | ecf/ 203 | rcf/ 204 | 205 | # Windows Store app package directories and files 206 | AppPackages/ 207 | BundleArtifacts/ 208 | Package.StoreAssociation.xml 209 | _pkginfo.txt 210 | *.appx 211 | *.appxbundle 212 | *.appxupload 213 | 214 | # Visual Studio cache files 215 | # files ending in .cache can be ignored 216 | *.[Cc]ache 217 | # but keep track of directories ending in .cache 218 | !?*.[Cc]ache/ 219 | 220 | # Others 221 | ClientBin/ 222 | ~$* 223 | *~ 224 | *.dbmdl 225 | *.dbproj.schemaview 226 | *.jfm 227 | *.pfx 228 | *.publishsettings 229 | orleans.codegen.cs 230 | 231 | # Including strong name files can present a security risk 232 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 233 | #*.snk 234 | 235 | # Since there are multiple workflows, uncomment next line to ignore bower_components 236 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 237 | #bower_components/ 238 | 239 | # RIA/Silverlight projects 240 | Generated_Code/ 241 | 242 | # Backup & report files from converting an old project file 243 | # to a newer Visual Studio version. Backup files are not needed, 244 | # because we have git ;-) 245 | _UpgradeReport_Files/ 246 | Backup*/ 247 | UpgradeLog*.XML 248 | UpgradeLog*.htm 249 | ServiceFabricBackup/ 250 | *.rptproj.bak 251 | 252 | # SQL Server files 253 | *.mdf 254 | *.ldf 255 | *.ndf 256 | 257 | # Business Intelligence projects 258 | *.rdl.data 259 | *.bim.layout 260 | *.bim_*.settings 261 | *.rptproj.rsuser 262 | *- [Bb]ackup.rdl 263 | *- [Bb]ackup ([0-9]).rdl 264 | *- [Bb]ackup ([0-9][0-9]).rdl 265 | 266 | # Microsoft Fakes 267 | FakesAssemblies/ 268 | 269 | # GhostDoc plugin setting file 270 | *.GhostDoc.xml 271 | 272 | # Node.js Tools for Visual Studio 273 | .ntvs_analysis.dat 274 | node_modules/ 275 | 276 | # Visual Studio 6 build log 277 | *.plg 278 | 279 | # Visual Studio 6 workspace options file 280 | *.opt 281 | 282 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 283 | *.vbw 284 | 285 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 286 | *.vbp 287 | 288 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 289 | *.dsw 290 | *.dsp 291 | 292 | # Visual Studio 6 technical files 293 | *.ncb 294 | *.aps 295 | 296 | # Visual Studio LightSwitch build output 297 | **/*.HTMLClient/GeneratedArtifacts 298 | **/*.DesktopClient/GeneratedArtifacts 299 | **/*.DesktopClient/ModelManifest.xml 300 | **/*.Server/GeneratedArtifacts 301 | **/*.Server/ModelManifest.xml 302 | _Pvt_Extensions 303 | 304 | # Paket dependency manager 305 | .paket/paket.exe 306 | paket-files/ 307 | 308 | # FAKE - F# Make 309 | .fake/ 310 | 311 | # CodeRush personal settings 312 | .cr/personal 313 | 314 | # Python Tools for Visual Studio (PTVS) 315 | __pycache__/ 316 | *.pyc 317 | 318 | # Cake - Uncomment if you are using it 319 | # tools/** 320 | # !tools/packages.config 321 | 322 | # Tabs Studio 323 | *.tss 324 | 325 | # Telerik's JustMock configuration file 326 | *.jmconfig 327 | 328 | # BizTalk build output 329 | *.btp.cs 330 | *.btm.cs 331 | *.odx.cs 332 | *.xsd.cs 333 | 334 | # OpenCover UI analysis results 335 | OpenCover/ 336 | 337 | # Azure Stream Analytics local run output 338 | ASALocalRun/ 339 | 340 | # MSBuild Binary and Structured Log 341 | *.binlog 342 | 343 | # NVidia Nsight GPU debugger configuration file 344 | *.nvuser 345 | 346 | # MFractors (Xamarin productivity tool) working folder 347 | .mfractor/ 348 | 349 | # Local History for Visual Studio 350 | .localhistory/ 351 | 352 | # Visual Studio History (VSHistory) files 353 | .vshistory/ 354 | 355 | # BeatPulse healthcheck temp database 356 | healthchecksdb 357 | 358 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 359 | MigrationBackup/ 360 | 361 | # Ionide (cross platform F# VS Code tools) working folder 362 | .ionide/ 363 | 364 | # Fody - auto-generated XML schema 365 | FodyWeavers.xsd 366 | 367 | # VS Code files for those working on multiple tools 368 | .vscode/* 369 | !.vscode/settings.json 370 | !.vscode/tasks.json 371 | !.vscode/launch.json 372 | !.vscode/extensions.json 373 | *.code-workspace 374 | 375 | # Local History for Visual Studio Code 376 | .history/ 377 | 378 | # Windows Installer files from build outputs 379 | *.cab 380 | *.msi 381 | *.msix 382 | *.msm 383 | *.msp 384 | 385 | # JetBrains Rider 386 | *.sln.iml -------------------------------------------------------------------------------- /ClsidExplorer/CLSIDExplorer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34009.444 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CLSIDExplorer", "CLSIDExplorer\CLSIDExplorer.vcxproj", "{F95126BB-346E-4791-852A-03E7CE87B513}" 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 | {F95126BB-346E-4791-852A-03E7CE87B513}.Debug|x64.ActiveCfg = Debug|x64 17 | {F95126BB-346E-4791-852A-03E7CE87B513}.Debug|x64.Build.0 = Debug|x64 18 | {F95126BB-346E-4791-852A-03E7CE87B513}.Debug|x86.ActiveCfg = Debug|Win32 19 | {F95126BB-346E-4791-852A-03E7CE87B513}.Debug|x86.Build.0 = Debug|Win32 20 | {F95126BB-346E-4791-852A-03E7CE87B513}.Release|x64.ActiveCfg = Release|x64 21 | {F95126BB-346E-4791-852A-03E7CE87B513}.Release|x64.Build.0 = Release|x64 22 | {F95126BB-346E-4791-852A-03E7CE87B513}.Release|x86.ActiveCfg = Release|Win32 23 | {F95126BB-346E-4791-852A-03E7CE87B513}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {A1707595-5EAC-49C3-865C-A926F0E3EACF} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /ClsidExplorer/CLSIDExplorer/CLSIDExplorer.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 | 17.0 23 | Win32Proj 24 | {f95126bb-346e-4791-852a-03e7ce87b513} 25 | CLSIDExplorer 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | true 77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | Console 82 | true 83 | 84 | 85 | 86 | 87 | Level3 88 | true 89 | true 90 | true 91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | true 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | true 118 | true 119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /ClsidExplorer/CLSIDExplorer/CLSIDExplorer.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Исходные файлы 20 | 21 | 22 | Исходные файлы 23 | 24 | 25 | 26 | 27 | Файлы заголовков 28 | 29 | 30 | Файлы заголовков 31 | 32 | 33 | -------------------------------------------------------------------------------- /ClsidExplorer/CLSIDExplorer/CLSIDExplorer.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --clsid {00000618-0000-0010-8000-00aa006d2ea4} 5 | WindowsLocalDebugger 6 | 7 | -------------------------------------------------------------------------------- /ClsidExplorer/CLSIDExplorer/Parser.cpp: -------------------------------------------------------------------------------- 1 | #include "Parser.h" 2 | 3 | 4 | DWORD Registry::GetAppIdFromClsid(IN std::wstring clsid, OUT std::wstring& appId) 5 | { 6 | HKEY hClsidKey; 7 | std::wstring clsidSubKey = L"CLSID\\" + clsid; 8 | if (RegOpenKeyEx(HKEY_CLASSES_ROOT, clsidSubKey.c_str(), 0, KEY_READ, &hClsidKey) != ERROR_SUCCESS) 9 | { 10 | return ERROR_OPEN_FAILED; 11 | } 12 | 13 | TCHAR valueBuffer[256]; 14 | DWORD valueBufferSize = sizeof(valueBuffer); 15 | 16 | if (RegQueryValueEx(hClsidKey, L"AppID", NULL, NULL, (LPBYTE)valueBuffer, &valueBufferSize) == ERROR_SUCCESS) 17 | { 18 | appId = valueBuffer; 19 | } 20 | else 21 | { 22 | return ERROR_NOT_FOUND; 23 | } 24 | 25 | RegCloseKey(hClsidKey); 26 | 27 | return ERROR_SUCCESS; 28 | } 29 | 30 | DWORD Registry::GetProgIdFromClsid(IN std::wstring clsid, OUT std::wstring& progId) 31 | { 32 | HKEY hKey; 33 | if (RegOpenKeyEx(HKEY_CLASSES_ROOT, NULL, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 34 | { 35 | return ERROR_OPEN_FAILED; 36 | } 37 | 38 | DWORD index = 0; 39 | TCHAR subKeyName[256]; 40 | DWORD subKeyNameSize = sizeof(subKeyName) / sizeof(subKeyName[0]); 41 | LONG ret = ERROR_SUCCESS; 42 | 43 | while ((ret = RegEnumKeyEx(hKey, index, subKeyName, &subKeyNameSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS) 44 | { 45 | HKEY hSubKey; 46 | 47 | if (RegOpenKeyEx(hKey, subKeyName, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) 48 | { 49 | DWORD valueBufferSize = 0; 50 | if (RegQueryValueEx(hSubKey, L"CLSID", NULL, NULL, NULL, &valueBufferSize) == ERROR_SUCCESS) 51 | { 52 | TCHAR* valueBuffer = new TCHAR[valueBufferSize / sizeof(TCHAR)]; 53 | if (RegQueryValueEx(hSubKey, L"CLSID", NULL, NULL, (LPBYTE)valueBuffer, &valueBufferSize) == ERROR_SUCCESS) 54 | { 55 | if (clsid == valueBuffer) 56 | { 57 | progId = subKeyName; 58 | delete[] valueBuffer; 59 | RegCloseKey(hSubKey); 60 | RegCloseKey(hKey); 61 | return ERROR_SUCCESS; 62 | } 63 | } 64 | delete[] valueBuffer; 65 | } 66 | RegCloseKey(hSubKey); 67 | } 68 | 69 | subKeyNameSize = sizeof(subKeyName) / sizeof(subKeyName[0]); 70 | index++; 71 | } 72 | 73 | RegCloseKey(hKey); 74 | return ERROR_NOT_FOUND; 75 | } 76 | 77 | DWORD Registry::GetRunAsKeyFromAppId(IN std::wstring appId, OUT std::wstring& runAs) 78 | { 79 | std::wstring appIdSubKey = L"AppID\\" + appId; 80 | HKEY hAppIdKey; 81 | if (RegOpenKeyEx(HKEY_CLASSES_ROOT, appIdSubKey.c_str(), 0, KEY_READ, &hAppIdKey) == ERROR_SUCCESS) 82 | { 83 | DWORD valueBufferSize = 256; 84 | TCHAR* valueBuffer = new TCHAR[valueBufferSize / sizeof(TCHAR)]; 85 | if (RegQueryValueEx(hAppIdKey, L"RunAs", NULL, NULL, (LPBYTE)valueBuffer, &valueBufferSize) == ERROR_SUCCESS) 86 | { 87 | runAs = valueBuffer; 88 | return ERROR_SUCCESS; 89 | } 90 | RegCloseKey(hAppIdKey); 91 | } 92 | return ERROR_OBJECT_NOT_FOUND; 93 | } 94 | 95 | 96 | std::wstring TypeLib::GetTypeName(ITypeInfo* pTypeInfo, TYPEDESC* pTypeDesc) 97 | { 98 | CComBSTR bstrName; 99 | HRESULT hr = S_OK; 100 | 101 | switch (pTypeDesc->vt) 102 | { 103 | case VT_I2: return L"short"; 104 | case VT_I4: return L"long"; 105 | case VT_R4: return L"float"; 106 | case VT_R8: return L"double"; 107 | case VT_CY: return L"CURRENCY"; 108 | case VT_DATE: return L"DATE"; 109 | case VT_BSTR: return L"BSTR"; 110 | case VT_DISPATCH: return L"IDispatch*"; 111 | case VT_ERROR: return L"SCODE"; 112 | case VT_BOOL: return L"VARIANT_BOOL"; 113 | case VT_VARIANT: return L"VARIANT"; 114 | case VT_UNKNOWN: return L"IUnknown*"; 115 | case VT_DECIMAL: return L"DECIMAL"; 116 | case VT_I1: return L"char"; 117 | case VT_UI1: return L"unsigned char"; 118 | case VT_UI2: return L"unsigned short"; 119 | case VT_UI4: return L"unsigned long"; 120 | case VT_INT: return L"int"; 121 | case VT_UINT: return L"unsigned int"; 122 | case VT_HRESULT: return L"HRESULT"; 123 | case VT_VOID: return L"void"; 124 | case VT_LPSTR: return L"LPSTR"; 125 | case VT_LPWSTR: return L"LPWSTR"; 126 | case VT_PTR: 127 | return GetTypeName(pTypeInfo, pTypeDesc->lptdesc) + L"*"; 128 | case VT_USERDEFINED: 129 | { 130 | CComPtr spRefTypeInfo; 131 | hr = pTypeInfo->GetRefTypeInfo(pTypeDesc->hreftype, &spRefTypeInfo); 132 | if (SUCCEEDED(hr)) 133 | { 134 | TYPEATTR* pRefTypeAttr; 135 | hr = spRefTypeInfo->GetTypeAttr(&pRefTypeAttr); 136 | if (SUCCEEDED(hr)) 137 | { 138 | spRefTypeInfo->GetDocumentation(MEMBERID_NIL, &bstrName, NULL, NULL, NULL); 139 | spRefTypeInfo->ReleaseTypeAttr(pRefTypeAttr); 140 | return std::wstring(bstrName); 141 | } 142 | } 143 | } 144 | break; 145 | default: 146 | break; 147 | } 148 | 149 | return L"unknown"; 150 | } 151 | 152 | DWORD TypeLib::GetMethodsFromTypelib(IN IUnknown* pUnknown, OUT std::vector& methods) 153 | { 154 | CComPtr pDispatch = nullptr; 155 | HRESULT hr; 156 | 157 | hr = pUnknown->QueryInterface(IID_IDispatch, (void**)&pDispatch); 158 | if (FAILED(hr)) 159 | return hr; 160 | 161 | CComPtr spTypeInfo; 162 | TYPEATTR* pTypeAttr = nullptr; 163 | 164 | hr = pDispatch->GetTypeInfo(0, LOCALE_USER_DEFAULT, &spTypeInfo); 165 | if (FAILED(hr)) 166 | { 167 | std::wcout << L"Failed to get type info." << std::endl; 168 | return hr; 169 | } 170 | 171 | hr = spTypeInfo->GetTypeAttr(&pTypeAttr); 172 | if (FAILED(hr)) 173 | { 174 | std::wcout << L"Failed to get type attributes." << std::endl; 175 | return hr; 176 | } 177 | 178 | for (UINT i = 0; i < pTypeAttr->cFuncs; ++i) 179 | { 180 | FUNCDESC* pFuncDesc = nullptr; 181 | hr = spTypeInfo->GetFuncDesc(i, &pFuncDesc); 182 | if (SUCCEEDED(hr)) 183 | { 184 | BSTR bstrName; 185 | UINT cNames; 186 | hr = spTypeInfo->GetNames(pFuncDesc->memid, &bstrName, 1, &cNames); 187 | if (SUCCEEDED(hr)) 188 | { 189 | std::wstring returnType = GetTypeName(spTypeInfo, &pFuncDesc->elemdescFunc.tdesc); 190 | 191 | std::wstring callConv; 192 | switch (pFuncDesc->callconv) 193 | { 194 | case CC_FASTCALL: 195 | callConv = L"__fastcall"; 196 | break; 197 | case CC_CDECL: 198 | callConv = L"__cdecl"; 199 | break; 200 | case CC_MPWPASCAL: 201 | case CC_PASCAL: 202 | callConv = L"__pascal"; 203 | break; 204 | case CC_MACPASCAL: 205 | callConv = L"__macpascal"; 206 | break; 207 | case CC_MPWCDECL: 208 | case CC_SYSCALL: 209 | case CC_STDCALL: 210 | callConv = L"__stdcall"; 211 | break; 212 | case CC_FPFASTCALL: 213 | callConv = L"__fpfastcall"; 214 | break; 215 | default: 216 | callConv = L""; 217 | break; 218 | } 219 | 220 | std::wstring params; 221 | for (UINT j = 0; j < pFuncDesc->cParams; ++j) 222 | { 223 | if (j > 0) params += L", "; 224 | 225 | std::wstring paramFlag; 226 | if (pFuncDesc->lprgelemdescParam[j].paramdesc.wParamFlags & PARAMFLAG_FIN) 227 | paramFlag += L"IN "; 228 | if (pFuncDesc->lprgelemdescParam[j].paramdesc.wParamFlags & PARAMFLAG_FOUT) 229 | paramFlag += L"OUT "; 230 | 231 | params += paramFlag + GetTypeName(spTypeInfo, &pFuncDesc->lprgelemdescParam[j].tdesc); 232 | } 233 | 234 | methods.push_back(callConv + L" " + returnType + L" " + bstrName + L"(" + params + L")"); 235 | 236 | 237 | SysFreeString(bstrName); 238 | } 239 | spTypeInfo->ReleaseFuncDesc(pFuncDesc); 240 | } 241 | } 242 | 243 | spTypeInfo->ReleaseTypeAttr(pTypeAttr); 244 | 245 | return ERROR_SUCCESS; 246 | } 247 | 248 | std::wstring Process::GetUserNameFromSID(PSID sid) 249 | { 250 | WCHAR name[256]; 251 | WCHAR domain[256]; 252 | DWORD nameSize = sizeof(name) / sizeof(WCHAR); 253 | DWORD domainSize = sizeof(domain) / sizeof(WCHAR); 254 | SID_NAME_USE sidUse; 255 | 256 | if (!LookupAccountSid(NULL, sid, name, &nameSize, domain, &domainSize, &sidUse)) 257 | return L""; 258 | 259 | std::wstring fullName(domain); 260 | fullName += L"\\\\"; 261 | fullName += name; 262 | 263 | return fullName; 264 | } 265 | 266 | std::wstring Process::GetProcessUserName(DWORD pid) 267 | { 268 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); 269 | if (!hProcess) 270 | return L""; 271 | 272 | HANDLE hToken; 273 | if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) 274 | { 275 | CloseHandle(hProcess); 276 | return L""; 277 | } 278 | 279 | DWORD bufferSize = 0; 280 | GetTokenInformation(hToken, TokenUser, NULL, 0, &bufferSize); 281 | 282 | if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 283 | { 284 | CloseHandle(hToken); 285 | CloseHandle(hProcess); 286 | return L""; 287 | } 288 | 289 | std::vector buffer(bufferSize); 290 | if (!GetTokenInformation(hToken, TokenUser, buffer.data(), bufferSize, &bufferSize)) 291 | { 292 | CloseHandle(hToken); 293 | CloseHandle(hProcess); 294 | return L""; 295 | } 296 | 297 | PSID sid = reinterpret_cast(buffer.data())->User.Sid; 298 | std::wstring userName = Process::GetUserNameFromSID(sid); 299 | 300 | CloseHandle(hToken); 301 | CloseHandle(hProcess); 302 | 303 | return userName; 304 | } 305 | 306 | BOOL Process::GetPIDFromIUnknown(IN IUnknown* pUnknown, OUT DWORD* pid) 307 | { 308 | CComPtr marshalStream; 309 | CreateStreamOnHGlobal(NULL, TRUE, &marshalStream); 310 | 311 | CoMarshalInterface( 312 | marshalStream, 313 | IID_IUnknown, 314 | pUnknown, 315 | MSHCTX_INPROC, 316 | NULL, 317 | MSHLFLAGS_NORMAL 318 | ); 319 | 320 | HGLOBAL memoryHandleFromStream = NULL; 321 | GetHGlobalFromStream(marshalStream, &memoryHandleFromStream); 322 | 323 | LPOBJREF objref = reinterpret_cast (GlobalLock(memoryHandleFromStream)); 324 | if (objref && objref->signature == OBJREF_SIGNATURE) 325 | { 326 | IPID ipid; 327 | 328 | if (objref->flags == OBJREF_STANDARD) 329 | { 330 | ipid = objref->u_objref.u_standard.std.ipid; 331 | } 332 | else if (objref->flags == OBJREF_HANDLER) 333 | { 334 | ipid = objref->u_objref.u_handler.std.ipid; 335 | } 336 | else if (objref->flags == OBJREF_EXTENDED) 337 | { 338 | ipid = objref->u_objref.u_extended.std.ipid; 339 | } 340 | else if (objref->flags == OBJREF_CUSTOM) 341 | { 342 | return FALSE; 343 | } 344 | 345 | static const int COM_SERVER_PID_OFFSET = 4; 346 | 347 | *pid = *reinterpret_cast( 348 | (reinterpret_cast(&ipid) + COM_SERVER_PID_OFFSET) 349 | ); 350 | return *pid != 0xffff; 351 | } 352 | } 353 | 354 | std::wstring Process::GetProcessName(DWORD processID) { 355 | std::wstring processName = L""; 356 | 357 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); 358 | 359 | if (NULL != hProcess) { 360 | HMODULE hMod; 361 | DWORD cbNeeded; 362 | 363 | if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) { 364 | wchar_t szProcessName[MAX_PATH]; 365 | if (GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName) / sizeof(wchar_t))) { 366 | processName = szProcessName; 367 | } 368 | } 369 | else 370 | { 371 | std::wcout << L"[-] EnumProcessModules() Failed: " << GetLastError() << std::endl; 372 | } 373 | 374 | CloseHandle(hProcess); 375 | } 376 | 377 | return processName; 378 | } -------------------------------------------------------------------------------- /ClsidExplorer/CLSIDExplorer/Parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static class Registry 11 | { 12 | public: 13 | static DWORD GetAppIdFromClsid(IN std::wstring clsid, OUT std::wstring& appId); 14 | static DWORD GetProgIdFromClsid(IN std::wstring clsid, OUT std::wstring& progId); 15 | static DWORD GetRunAsKeyFromAppId(IN std::wstring appId, OUT std::wstring& runAs); 16 | 17 | private: 18 | 19 | }; 20 | 21 | static class TypeLib 22 | { 23 | public: 24 | static DWORD GetMethodsFromTypelib(IN IUnknown* pUnknown, OUT std::vector& methods); 25 | static std::wstring GetTypeName(ITypeInfo* pTypeInfo, TYPEDESC* pTypeDesc); 26 | }; 27 | 28 | 29 | static class Process 30 | { 31 | public: 32 | static std::wstring GetProcessUserName(DWORD pid); 33 | static std::wstring GetProcessName(DWORD processID); 34 | static std::wstring GetUserNameFromSID(PSID sid); 35 | static BOOL GetPIDFromIUnknown(IN IUnknown* pUnknown, OUT DWORD* pid); 36 | }; 37 | 38 | 39 | 40 | typedef struct tagDATAELEMENT 41 | { 42 | GUID dataID; 43 | unsigned long cbSize; 44 | unsigned long cbRounded; 45 | /* [size_is] */ BYTE Data[1]; 46 | } DATAELEMENT; 47 | 48 | typedef struct tagDUALSTRINGARRAY 49 | { 50 | unsigned short wNumEntries; 51 | unsigned short wSecurityOffset; 52 | /* [size_is] */ unsigned short aStringArray[1]; 53 | } DUALSTRINGARRAY; 54 | 55 | typedef unsigned __int64 OXID; 56 | typedef unsigned __int64 OID; 57 | typedef GUID IPID; 58 | 59 | typedef struct tagOBJREFDATA 60 | { 61 | unsigned long nElms; 62 | /* [unique][size_is][size_is] */ DATAELEMENT** ppElmArray; 63 | } OBJREFDATA; 64 | 65 | typedef struct tagSTDOBJREF { 66 | unsigned long flags; 67 | unsigned long cPublicRefs; 68 | OXID oxid; 69 | OID oid; 70 | IPID ipid; 71 | } STDOBJREF; 72 | 73 | typedef struct tagOBJREF { 74 | unsigned long signature; 75 | unsigned long flags; 76 | GUID iid; 77 | union { 78 | struct { 79 | STDOBJREF std; 80 | DUALSTRINGARRAY saResAddr; 81 | } u_standard; 82 | struct { 83 | STDOBJREF std; 84 | CLSID clsid; 85 | DUALSTRINGARRAY saResAddr; 86 | } u_handler; 87 | struct { 88 | CLSID clsid; 89 | unsigned long cbExtension; 90 | unsigned long size; 91 | byte* pData; 92 | } u_custom; 93 | struct { 94 | STDOBJREF std; 95 | unsigned long Signature1; 96 | DUALSTRINGARRAY saResAddr; 97 | unsigned long nElms; 98 | unsigned long Signature2; 99 | DATAELEMENT ElmArray; 100 | } u_extended; 101 | } u_objref; 102 | } OBJREF, * LPOBJREF; 103 | 104 | typedef struct _IPID_ENTRY { 105 | IID iid; 106 | IPID ipid; // IPID to bind to 107 | OXID oxid; // Object Exporter ID 108 | OID oid; 109 | } IPID_ENTRY, * PIPID_ENTRY; 110 | 111 | 112 | #define OBJREF_SIGNATURE ( 0x574f454d ) 113 | 114 | #define OBJREF_STANDARD ( 0x1 ) 115 | #define OBJREF_HANDLER ( 0x2 ) 116 | #define OBJREF_CUSTOM ( 0x4 ) 117 | #define OBJREF_EXTENDED ( 0x8 ) -------------------------------------------------------------------------------- /ClsidExplorer/CLSIDExplorer/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "Parser.h" 3 | 4 | void ShowHelp() 5 | { 6 | std::wcout << L"CLSIDExplorer.exe - get all info about clsid" << std::endl; 7 | std::wcout << L"Usage:" << std::endl; 8 | std::wcout << L".\\CLSIDExplorer.exe --clsid \"{00000618-0000-0010-8000-00aa006d2ea4}\"" << std::endl; 9 | } 10 | 11 | int wmain(int argc, wchar_t* argv[]) 12 | { 13 | setlocale(LC_ALL, ""); 14 | 15 | std::wstring wsclsid; 16 | for (int i = 1; i < argc; ++i) { 17 | if (std::wstring(argv[i]) == L"--clsid" && i + 1 < argc) { 18 | wsclsid = argv[i + 1]; 19 | } 20 | } 21 | 22 | if (argc != 3 || wsclsid.size() == 0) 23 | { 24 | ShowHelp(); 25 | return -1; 26 | } 27 | 28 | std::wcout << L"[" << wsclsid << L"]" << std::endl; 29 | 30 | CoInitialize(NULL); 31 | 32 | HRESULT hr; 33 | 34 | CLSID clsid; 35 | hr = CLSIDFromString(wsclsid.c_str(), &clsid); 36 | if (FAILED(hr)) 37 | { 38 | std::wcout << L"[-] Cannot convert to CLSID: " << wsclsid << std::endl; 39 | return hr; 40 | } 41 | 42 | std::wstring appId; 43 | if (Registry::GetAppIdFromClsid(wsclsid, appId) == ERROR_SUCCESS) 44 | { 45 | std::wcout << L"\tAppID: " << appId << std::endl; 46 | } 47 | else { 48 | std::wcout << L"\tAppID: Unknown" << std::endl; 49 | } 50 | 51 | std::wstring progId; 52 | if (Registry::GetProgIdFromClsid(wsclsid, progId) == ERROR_SUCCESS) 53 | { 54 | std::wcout << L"\tProgID: " << progId << std::endl; 55 | } 56 | else { 57 | std::wcout << L"\tProgID: Unknown" << std::endl; 58 | } 59 | 60 | std::wstring runAs; 61 | if (!appId.empty()) 62 | { 63 | if (Registry::GetRunAsKeyFromAppId(appId, runAs) == ERROR_SUCCESS) 64 | { 65 | std::wcout << L"\tRunAs: " << runAs << std::endl; 66 | } 67 | else { 68 | std::wcout << L"\tRunAs: The launching user" << std::endl; 69 | } 70 | } 71 | 72 | CComPtr pUnknown = nullptr; 73 | 74 | hr = CoCreateInstance(clsid, 75 | nullptr, 76 | CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, 77 | IID_IUnknown, 78 | reinterpret_cast(&pUnknown)); 79 | 80 | DWORD pid; 81 | if (Process::GetPIDFromIUnknown(pUnknown, &pid)) 82 | { 83 | std::wcout << L"\tPID: " << pid << std::endl; 84 | 85 | std::wcout << L"\tProcess Name: " << Process::GetProcessName(pid) << std::endl; 86 | 87 | std::wcout << L"\tUsername: " << Process::GetProcessUserName(pid) << std::endl; 88 | 89 | } 90 | else { 91 | std::wcout << L"\tPID: Unknown" << std::endl; 92 | } 93 | 94 | std::vector methods; 95 | 96 | if (TypeLib::GetMethodsFromTypelib(pUnknown, methods) == ERROR_SUCCESS) 97 | { 98 | std::wcout << "\tMethods:" << std::endl; 99 | 100 | for (int i = 0; i < methods.size(); i++) 101 | { 102 | std::wcout << " \t[" << i << L"] " << methods[i] << std::endl; 103 | } 104 | } 105 | 106 | 107 | std::wcout << L"[END]" << std::endl; 108 | 109 | return 0; 110 | } -------------------------------------------------------------------------------- /ClsidExplorer/CLSIDExplorer/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include -------------------------------------------------------------------------------- /ClsidExplorer/x64/Debug/CLSIDExplorer.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/ClsidExplorer/x64/Debug/CLSIDExplorer.exe -------------------------------------------------------------------------------- /ClsidExplorer/x64/Debug/CLSIDExplorer.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/ClsidExplorer/x64/Debug/CLSIDExplorer.pdb -------------------------------------------------------------------------------- /ComDiver/COMDiver.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34009.444 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "COMDiver", "COMDiver\COMDiver.vcxproj", "{3930EDD4-E045-4374-AD0F-F4DF414A393A}" 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 | {3930EDD4-E045-4374-AD0F-F4DF414A393A}.Debug|x64.ActiveCfg = Debug|x64 17 | {3930EDD4-E045-4374-AD0F-F4DF414A393A}.Debug|x64.Build.0 = Debug|x64 18 | {3930EDD4-E045-4374-AD0F-F4DF414A393A}.Debug|x86.ActiveCfg = Debug|Win32 19 | {3930EDD4-E045-4374-AD0F-F4DF414A393A}.Debug|x86.Build.0 = Debug|Win32 20 | {3930EDD4-E045-4374-AD0F-F4DF414A393A}.Release|x64.ActiveCfg = Release|x64 21 | {3930EDD4-E045-4374-AD0F-F4DF414A393A}.Release|x64.Build.0 = Release|x64 22 | {3930EDD4-E045-4374-AD0F-F4DF414A393A}.Release|x86.ActiveCfg = Release|Win32 23 | {3930EDD4-E045-4374-AD0F-F4DF414A393A}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {2FD2A10C-7BE0-4E0F-AD1C-128D69CAA423} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /ComDiver/COMDiver/COMDiver.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 | 17.0 23 | Win32Proj 24 | {3930edd4-e045-4374-ad0f-f4df414a393a} 25 | COMDiver 26 | 10.0 27 | ComDiver 28 | 29 | 30 | 31 | Application 32 | true 33 | v143 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v143 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v143 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v143 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 | 76 | Level3 77 | true 78 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 79 | true 80 | 81 | 82 | Console 83 | true 84 | 85 | 86 | 87 | 88 | Level3 89 | true 90 | true 91 | true 92 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 93 | true 94 | 95 | 96 | Console 97 | true 98 | true 99 | true 100 | 101 | 102 | 103 | 104 | Level3 105 | true 106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | true 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | true 119 | true 120 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | 123 | 124 | Console 125 | true 126 | true 127 | true 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /ComDiver/COMDiver/COMDiver.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Исходные файлы 20 | 21 | 22 | Исходные файлы 23 | 24 | 25 | Исходные файлы 26 | 27 | 28 | Исходные файлы 29 | 30 | 31 | 32 | 33 | Файлы заголовков 34 | 35 | 36 | Файлы заголовков 37 | 38 | 39 | Файлы заголовков 40 | 41 | 42 | Файлы заголовков 43 | 44 | 45 | -------------------------------------------------------------------------------- /ComDiver/COMDiver/COMDiver.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --target "{52B65EB7-907C-4D83-A535-283BE9104DE4}" 5 | WindowsLocalDebugger 6 | 7 | -------------------------------------------------------------------------------- /ComDiver/COMDiver/analyzer.cpp: -------------------------------------------------------------------------------- 1 | #include "analyzer.h" 2 | #include "enumerator.h" 3 | 4 | void SetConsoleColor(WORD color) 5 | { 6 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 7 | SetConsoleTextAttribute(hConsole, color); 8 | } 9 | 10 | std::wstring toLowerCase(const std::wstring& input) { 11 | std::wstring result = input; 12 | std::transform(result.begin(), result.end(), result.begin(), ::tolower); 13 | return result; 14 | } 15 | 16 | void WriteRedText(const std::wstring& text) 17 | { 18 | SetConsoleColor(FOREGROUND_RED | FOREGROUND_INTENSITY); 19 | 20 | std::wcout << text << std::endl; 21 | 22 | SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); 23 | } 24 | 25 | void WriteGreenText(const std::wstring& text) 26 | { 27 | SetConsoleColor(FOREGROUND_GREEN | FOREGROUND_INTENSITY); 28 | 29 | std::wcout << text << std::endl; 30 | 31 | SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); 32 | } 33 | 34 | bool CheckRegistryKeyExists(HKEY hive, const std::wstring& path) { 35 | HKEY hKey; 36 | DWORD res = RegOpenKeyEx(hive, path.c_str(), 0, KEY_READ, &hKey); 37 | if (res == ERROR_SUCCESS) { 38 | RegCloseKey(hKey); 39 | return true; 40 | } 41 | return false; 42 | } 43 | 44 | 45 | std::wstring GetFullPathFromPID(DWORD pid, const std::wstring& fileName) { 46 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); 47 | if (hProcess) { 48 | wchar_t processPath[MAX_PATH]; 49 | if (GetModuleFileNameEx(hProcess, NULL, processPath, MAX_PATH)) { 50 | wchar_t* filePart; 51 | if (GetFullPathName(fileName.c_str(), MAX_PATH, processPath, &filePart)) { 52 | CloseHandle(hProcess); 53 | return std::wstring(processPath); 54 | } 55 | } 56 | CloseHandle(hProcess); 57 | } 58 | return fileName; 59 | } 60 | 61 | std::wstring GetCurrentUsername() 62 | { 63 | wchar_t username[255 + 1]; 64 | DWORD username_len = 255 + 1; 65 | if (GetUserNameW(username, &username_len)) { 66 | return std::wstring(username); 67 | } 68 | else { 69 | return L""; 70 | } 71 | } 72 | 73 | std::wstring ExpandEnvironmentStringsIfNeeded(const std::wstring& input) { 74 | if (input.empty()) { 75 | return input; 76 | } 77 | 78 | std::vector expandedPath(MAX_PATH); 79 | DWORD result = ExpandEnvironmentStrings(input.c_str(), expandedPath.data(), MAX_PATH); 80 | if (result == 0 || result > MAX_PATH) { 81 | return input; 82 | } 83 | 84 | return std::wstring(expandedPath.data()); 85 | } 86 | 87 | std::wstring GetRegistryStringValue(HKEY hKeyRoot, const std::wstring& subKey) { 88 | HKEY hKey; 89 | LONG lResult = RegOpenKeyEx(hKeyRoot, subKey.c_str(), 0, KEY_READ, &hKey); 90 | 91 | if (lResult != ERROR_SUCCESS) { 92 | DWORD dw = GetLastError(); 93 | return L""; 94 | } 95 | 96 | DWORD dwType = 0; 97 | DWORD dwSize = 0; 98 | lResult = RegQueryValueEx(hKey, nullptr, nullptr, &dwType, nullptr, &dwSize); 99 | 100 | if (lResult != ERROR_SUCCESS || (dwType != REG_SZ && dwType != REG_EXPAND_SZ)) { 101 | RegCloseKey(hKey); 102 | return L""; 103 | } 104 | 105 | std::wstring value(dwSize / sizeof(wchar_t), L'\0'); 106 | lResult = RegQueryValueEx(hKey, nullptr, nullptr, nullptr, reinterpret_cast(&value[0]), &dwSize); 107 | 108 | RegCloseKey(hKey); 109 | 110 | if (lResult != ERROR_SUCCESS) { 111 | return L""; 112 | } 113 | 114 | if (!value.empty() && value.back() == L'\0') { 115 | value.pop_back(); 116 | } 117 | 118 | if (dwType == REG_EXPAND_SZ) { 119 | value = ExpandEnvironmentStringsIfNeeded(value); 120 | } 121 | 122 | return value; 123 | } 124 | 125 | bool CheckFileWriteAccess(const std::wstring& filePath) 126 | { 127 | DWORD filePermissions = GENERIC_WRITE; 128 | HANDLE hFile = CreateFile(filePath.c_str(), filePermissions, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); 129 | if (hFile == INVALID_HANDLE_VALUE) 130 | { 131 | DWORD dw = GetLastError(); 132 | return false; 133 | } 134 | else { 135 | CloseHandle(hFile); 136 | return true; 137 | } 138 | } 139 | 140 | std::wstring GetRootKeyName(HKEY hKey) { 141 | if (hKey == HKEY_CURRENT_USER) return L"HKCU"; 142 | if (hKey == HKEY_LOCAL_MACHINE) return L"HKLM"; 143 | if (hKey == HKEY_CLASSES_ROOT) return L"HKCR"; 144 | return L""; 145 | } 146 | 147 | std::pair FindPathFromRegistry(const std::wstring& clsid) 148 | { 149 | const std::wstring paths[] = { 150 | L"SOFTWARE\\Classes\\CLSID\\" + clsid + L"\\TreatAs", 151 | L"SOFTWARE\\Classes\\CLSID\\" + clsid + L"\\InprocServer32", 152 | L"SOFTWARE\\Classes\\CLSID\\" + clsid + L"\\LocalServer32" 153 | }; 154 | 155 | for (const auto& hKey : { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }) 156 | { 157 | for (const auto& partialPath : paths) 158 | { 159 | std::wstring value = GetRegistryStringValue(hKey, partialPath); 160 | if (!value.empty()) 161 | { 162 | std::wstring fullPath = GetRootKeyName(hKey) + L"\\" + partialPath; 163 | return { value, fullPath }; 164 | } 165 | } 166 | } 167 | 168 | return { L"", L"" }; 169 | } 170 | 171 | bool CheckRegistryWriteCreateAccess(HKEY hive, const std::wstring& path) 172 | { 173 | HKEY hKey; 174 | REGSAM samDesired = KEY_WRITE | KEY_CREATE_SUB_KEY; 175 | 176 | DWORD res = RegOpenKeyEx(hive, path.c_str(), 0, samDesired, &hKey); 177 | if (res == ERROR_SUCCESS) 178 | { 179 | RegCloseKey(hKey); 180 | return true; 181 | } 182 | 183 | res = RegCreateKeyEx(hive, path.c_str(), 0, NULL, 184 | REG_OPTION_VOLATILE, // temporary key 185 | KEY_WRITE | KEY_CREATE_SUB_KEY, 186 | NULL, &hKey, NULL); 187 | 188 | if (res == ERROR_SUCCESS) 189 | { 190 | RegCloseKey(hKey); 191 | 192 | RegDeleteKey(hive, path.c_str()); 193 | 194 | return true; 195 | } 196 | return false; 197 | } 198 | 199 | std::wstring GetFileName(const std::wstring& path) 200 | { 201 | if (path.empty()) { 202 | return L""; 203 | } 204 | 205 | size_t start = 0; 206 | size_t end = path.length(); 207 | 208 | if (path[0] == L'"') { 209 | start = 1; 210 | for (size_t i = start; i < path.length(); ++i) { 211 | if (path[i] == L'"') { 212 | end = i; 213 | break; 214 | } 215 | } 216 | } 217 | else { 218 | for (size_t i = 0; i < path.length(); ++i) { 219 | if (path[i] == L' ') { 220 | end = i; 221 | break; 222 | } 223 | } 224 | } 225 | 226 | return path.substr(start, end - start); 227 | } 228 | 229 | VOID AnalyzeCLSID(std::wstring& wsclsid, BOOL checkCreate, BOOL checkAnotherContext) 230 | { 231 | HRESULT hr; 232 | CComPtr pUnknown = nullptr; 233 | 234 | CLSID clsid; 235 | 236 | 237 | hr = CLSIDFromString(wsclsid.c_str(), &clsid); 238 | if (!SUCCEEDED(hr)) 239 | { 240 | //std::wcout << L"\t[-] Error in converting " << wsclsid << L" to CLSID" << std::endl; 241 | return; 242 | } 243 | 244 | std::wcout << L"----------------------------" << std::endl; 245 | std::wcout << L"----[" << wsclsid << L"]----" << std::endl; 246 | 247 | // Checking Create Rights 248 | if (checkCreate) 249 | { 250 | hr = CoCreateInstance(clsid, 251 | nullptr, 252 | CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, 253 | IID_IUnknown, 254 | reinterpret_cast(&pUnknown)); 255 | 256 | if (!SUCCEEDED(hr)) 257 | { 258 | std::wcout << L"\t[-] Error in CoCreateInstance: " << hr << L" CLSID: " << wsclsid << std::endl; 259 | return; 260 | } 261 | } 262 | 263 | std::wstring username = L""; 264 | std::wstring processName = L""; 265 | std::wstring runAs = L""; 266 | DWORD pid = 0; 267 | 268 | 269 | // Checking another user context 270 | if (checkAnotherContext) 271 | { 272 | std::wstring appId = L""; 273 | 274 | if (GetAppIdFromClsid(wsclsid, appId) != ERROR_SUCCESS) 275 | { 276 | //std::wcout << L"\t[-] Can't find AppId. May be there is no another context" << std::endl; 277 | return; 278 | } 279 | 280 | if (GetRunAsKeyFromAppId(appId, runAs) != ERROR_SUCCESS) 281 | { 282 | //std::wcout << L"\t[-] Cant get PID and cant get RunAs key -> NO ANOTHER CONTEXT" << std::endl; 283 | return; 284 | } 285 | 286 | if (GetPIDFromIUnknown(pUnknown, &pid) == TRUE) 287 | { 288 | std::wstring currentUsername = GetCurrentUsername(); 289 | username = GetProcessUserName(pid); 290 | 291 | if (username.find(currentUsername) != std::wstring::npos && runAs.empty()) 292 | { 293 | //std::wcout << L"\t[+] Running from current user: " << username << std::endl; 294 | // runAs.empty() <- NO Option Interactive User 295 | return; 296 | } 297 | 298 | processName = GetProcessName(pid); 299 | 300 | } 301 | } 302 | 303 | std::wcout << L"\t[+] Username: " << username << std::endl; 304 | std::wcout << L"\t[+] RunAs Value: " << runAs << std::endl; 305 | std::wcout << L"\t[+] Process: " << processName << std::endl; 306 | std::wcout << L"\t[+] PID: " << pid << std::endl; 307 | 308 | // Analiyzing Insecure Registry Permissions 309 | std::pair result = FindPathFromRegistry(wsclsid); 310 | 311 | if (result.first.empty()) 312 | { 313 | //std::wcout << L"No associated file found for CLSID " << wsclsid << std::endl; 314 | return; 315 | } 316 | 317 | std::wcout << L"\t[+] Disk Path: " << result.first << std::endl; 318 | std::wcout << L"\t[+] Registry Path: " << result.second << std::endl; 319 | 320 | std::wcout << L"\t[?] Load priority hijacking: " << std::endl; 321 | const std::wstring priorities[] = { 322 | L"HKCU\\Software\\Classes\\CLSID\\" + wsclsid + L"\\TreatAs", 323 | L"HKLM\\Software\\Classes\\CLSID\\" + wsclsid + L"\\TreatAs", 324 | L"HKCU\\Software\\Classes\\CLSID\\" + wsclsid + L"\\InprocServer32", 325 | L"HKLM\\Software\\Classes\\CLSID\\" + wsclsid + L"\\InprocServer32", 326 | L"HKCU\\Software\\Classes\\CLSID\\" + wsclsid + L"\\LocalServer32", 327 | L"HKLM\\Software\\Classes\\CLSID\\" + wsclsid + L"\\LocalServer32" 328 | }; 329 | 330 | for (size_t i = 0; i < std::size(priorities); ++i) { 331 | const auto& path = priorities[i]; 332 | HKEY hKey; 333 | if (path.find(L"HKCU") == 0) 334 | hKey = HKEY_CURRENT_USER; 335 | else if (path.find(L"HKLM") == 0) 336 | hKey = HKEY_LOCAL_MACHINE; 337 | else 338 | continue; 339 | 340 | bool exists = CheckRegistryKeyExists(hKey, path.substr(path.find_first_of(L'\\') + 1)); 341 | bool writable = CheckRegistryWriteCreateAccess(hKey, path.substr(path.find_first_of(L'\\') + 1)); 342 | 343 | std::wstring output = L"\t\t[" + std::to_wstring(i + 1) + L"] " + (writable ? L"Writable" : L"Non Writable") + L": "; 344 | output += path + L" (" + (exists ? L"Exists" : L"Does not exists") + L")"; 345 | 346 | if (writable) { 347 | WriteRedText(output); 348 | } 349 | else { 350 | std::wcout << output << std::endl; 351 | } 352 | 353 | if (toLowerCase(path) == toLowerCase(result.second)) 354 | { 355 | WriteGreenText(L"\t\t[" + std::to_wstring(i + 1) + L"] Real Path: " + path); 356 | break; 357 | } 358 | } 359 | 360 | 361 | // Analyzing File Disk Permissions 362 | std::wstring strippedPath = GetFileName(result.first); 363 | if (PathIsRelative(strippedPath.c_str())) { 364 | strippedPath = GetFullPathFromPID(pid, strippedPath); 365 | } 366 | 367 | if (CheckFileWriteAccess(strippedPath)) 368 | { 369 | WriteRedText(L"\t[+] Writable path on disk: " + strippedPath); 370 | } 371 | 372 | 373 | return; 374 | } -------------------------------------------------------------------------------- /ComDiver/COMDiver/analyzer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | VOID AnalyzeCLSID(std::wstring& clsid, BOOL checkCreate, BOOL checkAnotherContext); -------------------------------------------------------------------------------- /ComDiver/COMDiver/argparse.cpp: -------------------------------------------------------------------------------- 1 | #include "argparse.h" 2 | 3 | wchar_t* getCmdOption(wchar_t** begin, wchar_t** end, const std::wstring& option) 4 | { 5 | wchar_t** itr = std::find(begin, end, option); 6 | if (itr != end && ++itr != end) 7 | { 8 | return *itr; 9 | } 10 | return nullptr; 11 | } 12 | 13 | bool cmdOptionExists(wchar_t** begin, wchar_t** end, const std::wstring& option) 14 | { 15 | return std::find(begin, end, option) != end; 16 | } -------------------------------------------------------------------------------- /ComDiver/COMDiver/argparse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | bool cmdOptionExists(wchar_t** begin, wchar_t** end, const std::wstring& option); 6 | wchar_t* getCmdOption(wchar_t** begin, wchar_t** end, const std::wstring& option); -------------------------------------------------------------------------------- /ComDiver/COMDiver/enumerator.cpp: -------------------------------------------------------------------------------- 1 | #include "enumerator.h" 2 | 3 | std::vector EnumerateCLSID() 4 | { 5 | std::vector clsidList; 6 | HKEY hKey; 7 | LONG nError; 8 | 9 | nError = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"CLSID", 0, KEY_READ, &hKey); 10 | if (nError == ERROR_SUCCESS) 11 | { 12 | DWORD dwIndex = 0; 13 | WCHAR szName[MAX_PATH]; 14 | DWORD dwNameSize = _countof(szName); 15 | FILETIME ftLastWriteTime; 16 | 17 | while (RegEnumKeyEx(hKey, dwIndex, szName, &dwNameSize, NULL, NULL, NULL, &ftLastWriteTime) == ERROR_SUCCESS) 18 | { 19 | clsidList.push_back(szName); 20 | dwNameSize = _countof(szName); 21 | dwIndex++; 22 | } 23 | 24 | RegCloseKey(hKey); 25 | } 26 | else 27 | { 28 | std::wcerr << L"Cant open HKEY_CLASSES_ROOT\\CLSID. Error: " << nError << std::endl; 29 | } 30 | 31 | return clsidList; 32 | } 33 | 34 | DWORD GetAppIdFromClsid(IN std::wstring clsid, OUT std::wstring& appId) 35 | { 36 | HKEY hClsidKey; 37 | std::wstring clsidSubKey = L"CLSID\\" + clsid; 38 | if (RegOpenKeyEx(HKEY_CLASSES_ROOT, clsidSubKey.c_str(), 0, KEY_READ, &hClsidKey) != ERROR_SUCCESS) 39 | { 40 | return ERROR_OPEN_FAILED; 41 | } 42 | 43 | TCHAR valueBuffer[256]; 44 | DWORD valueBufferSize = sizeof(valueBuffer); 45 | 46 | if (RegQueryValueEx(hClsidKey, L"AppID", NULL, NULL, (LPBYTE)valueBuffer, &valueBufferSize) == ERROR_SUCCESS) 47 | { 48 | appId = valueBuffer; 49 | } 50 | 51 | RegCloseKey(hClsidKey); 52 | 53 | return ERROR_SUCCESS; 54 | } 55 | 56 | DWORD GetProgIdFromClsid(IN std::wstring clsid, OUT std::wstring& progId) 57 | { 58 | HKEY hKey; 59 | if (RegOpenKeyEx(HKEY_CLASSES_ROOT, NULL, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 60 | { 61 | return ERROR_OPEN_FAILED; 62 | } 63 | 64 | DWORD index = 0; 65 | TCHAR subKeyName[256]; 66 | DWORD subKeyNameSize = sizeof(subKeyName) / sizeof(subKeyName[0]); 67 | LONG ret = ERROR_SUCCESS; 68 | 69 | while ((ret = RegEnumKeyEx(hKey, index, subKeyName, &subKeyNameSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS) 70 | { 71 | HKEY hSubKey; 72 | 73 | if (RegOpenKeyEx(hKey, subKeyName, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) 74 | { 75 | DWORD valueBufferSize = 0; 76 | if (RegQueryValueEx(hSubKey, L"CLSID", NULL, NULL, NULL, &valueBufferSize) == ERROR_SUCCESS) 77 | { 78 | TCHAR* valueBuffer = new TCHAR[valueBufferSize / sizeof(TCHAR)]; 79 | if (RegQueryValueEx(hSubKey, L"CLSID", NULL, NULL, (LPBYTE)valueBuffer, &valueBufferSize) == ERROR_SUCCESS) 80 | { 81 | if (clsid == valueBuffer) 82 | { 83 | progId = subKeyName; 84 | delete[] valueBuffer; 85 | RegCloseKey(hSubKey); 86 | RegCloseKey(hKey); 87 | return ERROR_SUCCESS; 88 | } 89 | } 90 | delete[] valueBuffer; 91 | } 92 | RegCloseKey(hSubKey); 93 | } 94 | 95 | subKeyNameSize = sizeof(subKeyName) / sizeof(subKeyName[0]); 96 | index++; 97 | } 98 | 99 | RegCloseKey(hKey); 100 | return ERROR_NOT_FOUND; 101 | } 102 | 103 | DWORD GetRunAsKeyFromAppId(IN std::wstring appId, OUT std::wstring& runAs) 104 | { 105 | std::wstring appIdSubKey = L"AppID\\" + appId; 106 | HKEY hAppIdKey; 107 | if (RegOpenKeyEx(HKEY_CLASSES_ROOT, appIdSubKey.c_str(), 0, KEY_READ, &hAppIdKey) == ERROR_SUCCESS) 108 | { 109 | DWORD valueBufferSize = 256; 110 | TCHAR* valueBuffer = new TCHAR[valueBufferSize / sizeof(TCHAR)]; 111 | if (RegQueryValueEx(hAppIdKey, L"RunAs", NULL, NULL, (LPBYTE)valueBuffer, &valueBufferSize) == ERROR_SUCCESS) 112 | { 113 | runAs = valueBuffer; 114 | return ERROR_SUCCESS; 115 | } 116 | RegCloseKey(hAppIdKey); 117 | } 118 | return ERROR_OBJECT_NOT_FOUND; 119 | } 120 | 121 | std::wstring GetUserNameFromSID(PSID sid) 122 | { 123 | WCHAR name[256]; 124 | WCHAR domain[256]; 125 | DWORD nameSize = sizeof(name) / sizeof(WCHAR); 126 | DWORD domainSize = sizeof(domain) / sizeof(WCHAR); 127 | SID_NAME_USE sidUse; 128 | 129 | if (!LookupAccountSid(NULL, sid, name, &nameSize, domain, &domainSize, &sidUse)) 130 | return L""; 131 | 132 | std::wstring fullName(domain); 133 | fullName += L"\\\\"; 134 | fullName += name; 135 | 136 | return fullName; 137 | } 138 | 139 | std::wstring GetProcessUserName(DWORD pid) 140 | { 141 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); 142 | if (!hProcess) 143 | return L""; 144 | 145 | HANDLE hToken; 146 | if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) 147 | { 148 | CloseHandle(hProcess); 149 | return L""; 150 | } 151 | 152 | DWORD bufferSize = 0; 153 | GetTokenInformation(hToken, TokenUser, NULL, 0, &bufferSize); 154 | 155 | if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 156 | { 157 | CloseHandle(hToken); 158 | CloseHandle(hProcess); 159 | return L""; 160 | } 161 | 162 | std::vector buffer(bufferSize); 163 | if (!GetTokenInformation(hToken, TokenUser, buffer.data(), bufferSize, &bufferSize)) 164 | { 165 | CloseHandle(hToken); 166 | CloseHandle(hProcess); 167 | return L""; 168 | } 169 | 170 | PSID sid = reinterpret_cast(buffer.data())->User.Sid; 171 | std::wstring userName = GetUserNameFromSID(sid); 172 | 173 | CloseHandle(hToken); 174 | CloseHandle(hProcess); 175 | 176 | return userName; 177 | } 178 | 179 | BOOL GetPIDFromIUnknown(IN IUnknown* pUnknown, OUT DWORD* pid) 180 | { 181 | CComPtr marshalStream; 182 | CreateStreamOnHGlobal(NULL, TRUE, &marshalStream); 183 | 184 | CoMarshalInterface( 185 | marshalStream, 186 | IID_IUnknown, 187 | pUnknown, 188 | MSHCTX_INPROC, 189 | NULL, 190 | MSHLFLAGS_NORMAL 191 | ); 192 | 193 | HGLOBAL memoryHandleFromStream = NULL; 194 | GetHGlobalFromStream(marshalStream, &memoryHandleFromStream); 195 | 196 | LPOBJREF objref = reinterpret_cast (GlobalLock(memoryHandleFromStream)); 197 | if (objref && objref->signature == OBJREF_SIGNATURE) 198 | { 199 | IPID ipid; 200 | 201 | if (objref->flags == OBJREF_STANDARD) 202 | { 203 | ipid = objref->u_objref.u_standard.std.ipid; 204 | } 205 | else if (objref->flags == OBJREF_HANDLER) 206 | { 207 | ipid = objref->u_objref.u_handler.std.ipid; 208 | } 209 | else if (objref->flags == OBJREF_EXTENDED) 210 | { 211 | ipid = objref->u_objref.u_extended.std.ipid; 212 | } 213 | else if (objref->flags == OBJREF_CUSTOM) 214 | { 215 | return FALSE; 216 | } 217 | 218 | static const int COM_SERVER_PID_OFFSET = 4; 219 | 220 | *pid = *reinterpret_cast( 221 | (reinterpret_cast(&ipid) + COM_SERVER_PID_OFFSET) 222 | ); 223 | return *pid != 0xffff; 224 | } 225 | } 226 | 227 | std::wstring GetProcessName(DWORD processID) { 228 | std::wstring processName = L""; 229 | 230 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); 231 | 232 | if (NULL != hProcess) { 233 | HMODULE hMod; 234 | DWORD cbNeeded; 235 | 236 | if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) { 237 | wchar_t szProcessName[MAX_PATH]; 238 | if (GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName) / sizeof(wchar_t))) { 239 | processName = szProcessName; 240 | } 241 | } 242 | else 243 | { 244 | std::wcout << L"[-] EnumProcessModules() Failed: " << GetLastError() << std::endl; 245 | } 246 | 247 | CloseHandle(hProcess); 248 | } 249 | 250 | return processName; 251 | } -------------------------------------------------------------------------------- /ComDiver/COMDiver/enumerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | std::vector EnumerateCLSID(); 11 | DWORD GetAppIdFromClsid(IN std::wstring clsid, OUT std::wstring& appId); 12 | DWORD GetProgIdFromClsid(IN std::wstring clsid, OUT std::wstring& progId); 13 | DWORD GetRunAsKeyFromAppId(IN std::wstring appId, OUT std::wstring& runAs); 14 | BOOL GetPIDFromIUnknown(IN IUnknown* pUnknown, OUT DWORD* pid); 15 | std::wstring GetProcessUserName(DWORD pid); 16 | std::wstring GetProcessName(DWORD processID); 17 | 18 | typedef struct tagDATAELEMENT 19 | { 20 | GUID dataID; 21 | unsigned long cbSize; 22 | unsigned long cbRounded; 23 | /* [size_is] */ BYTE Data[1]; 24 | } DATAELEMENT; 25 | 26 | typedef struct tagDUALSTRINGARRAY 27 | { 28 | unsigned short wNumEntries; 29 | unsigned short wSecurityOffset; 30 | /* [size_is] */ unsigned short aStringArray[1]; 31 | } DUALSTRINGARRAY; 32 | 33 | typedef unsigned __int64 OXID; 34 | typedef unsigned __int64 OID; 35 | typedef GUID IPID; 36 | 37 | typedef struct tagOBJREFDATA 38 | { 39 | unsigned long nElms; 40 | /* [unique][size_is][size_is] */ DATAELEMENT** ppElmArray; 41 | } OBJREFDATA; 42 | 43 | typedef struct tagSTDOBJREF { 44 | unsigned long flags; 45 | unsigned long cPublicRefs; 46 | OXID oxid; 47 | OID oid; 48 | IPID ipid; 49 | } STDOBJREF; 50 | 51 | typedef struct tagOBJREF { 52 | unsigned long signature; 53 | unsigned long flags; 54 | GUID iid; 55 | union { 56 | struct { 57 | STDOBJREF std; 58 | DUALSTRINGARRAY saResAddr; 59 | } u_standard; 60 | struct { 61 | STDOBJREF std; 62 | CLSID clsid; 63 | DUALSTRINGARRAY saResAddr; 64 | } u_handler; 65 | struct { 66 | CLSID clsid; 67 | unsigned long cbExtension; 68 | unsigned long size; 69 | byte* pData; 70 | } u_custom; 71 | struct { 72 | STDOBJREF std; 73 | unsigned long Signature1; 74 | DUALSTRINGARRAY saResAddr; 75 | unsigned long nElms; 76 | unsigned long Signature2; 77 | DATAELEMENT ElmArray; 78 | } u_extended; 79 | } u_objref; 80 | } OBJREF, * LPOBJREF; 81 | 82 | typedef struct _IPID_ENTRY { 83 | IID iid; 84 | IPID ipid; // IPID to bind to 85 | OXID oxid; // Object Exporter ID 86 | OID oid; 87 | } IPID_ENTRY, * PIPID_ENTRY; 88 | 89 | 90 | #define OBJREF_SIGNATURE ( 0x574f454d ) 91 | 92 | #define OBJREF_STANDARD ( 0x1 ) 93 | #define OBJREF_HANDLER ( 0x2 ) 94 | #define OBJREF_CUSTOM ( 0x4 ) 95 | #define OBJREF_EXTENDED ( 0x8 ) -------------------------------------------------------------------------------- /ComDiver/COMDiver/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "argparse.h" 3 | #include "enumerator.h" 4 | #include "analyzer.h" 5 | 6 | 7 | LONG WINAPI MyVectoredExceptionHandler(PEXCEPTION_POINTERS exceptionInfo) 8 | { 9 | std::wcout << L"\t[!] Exception occurred!" << std::endl; 10 | 11 | std::wcout << L"\t[!] Exception Code: " << exceptionInfo->ExceptionRecord->ExceptionCode << std::endl; 12 | std::wcout << L"\t[!] Exception Address: " << exceptionInfo->ExceptionRecord->ExceptionAddress << std::endl; 13 | 14 | std::wcout << L"\t[!!!] If program had crashed pls restart using .\\COMDiver.exe --from " << std::endl; 15 | 16 | return EXCEPTION_EXECUTE_HANDLER; 17 | } 18 | 19 | void ShowHelp() 20 | { 21 | std::cout << R"( 22 | \ / 23 | \ o ^ o / 24 | \ ( ) / 25 | ____________(%%%%%%%)____________ 26 | ( / / )%%%%%%%( \ \ ) 27 | (___/___/__/ \__\___\___) 28 | ( / /(%%%%%%%)\ \ ) 29 | (__/___/ (%%%%%%%) \___\__) 30 | /( )\ 31 | / (%%%%%) \ 32 | (%%%) 33 | ! 34 | )" << std::endl; 35 | std::wcout << L"----------- COM DIVER --------------" << std::endl; 36 | std::wcout << L"[?] Small tool to check insecure registry and disk permissions on com objects" << std::endl; 37 | std::wcout << L"[?] ARGS" << std::endl; 38 | std::wcout << L"\t-h/--help <- show this message" << std::endl; 39 | std::wcout << L"\t--from <- analyze CLSIDs from this clsid" << std::endl; 40 | std::wcout << L"\t--target <- analyze one target clsid" << std::endl; 41 | std::wcout << L"\t--no-context <- dont check another COM-server context. Only registry analyzing." << std::endl; 42 | std::wcout << L"\t--no-create <- dont create target COM object. This is the fastest mode" << std::endl; 43 | } 44 | 45 | int wmain(int argc, wchar_t* argv[]) 46 | { 47 | setlocale(LC_ALL, ""); 48 | 49 | if (cmdOptionExists(argv, argv + argc, L"-h") || cmdOptionExists(argv, argv + argc, L"--help")) 50 | { 51 | ShowHelp(); 52 | return 0; 53 | } 54 | 55 | std::wstring targetClsid; 56 | if (cmdOptionExists(argv, argv + argc, L"--target")) 57 | { 58 | targetClsid = getCmdOption(argv, argv + argc, L"--target"); 59 | } 60 | 61 | std::wstring startFromClsid; 62 | if (cmdOptionExists(argv, argv + argc, L"--from")) 63 | { 64 | startFromClsid = getCmdOption(argv, argv + argc, L"--from"); 65 | } 66 | 67 | BOOL checkAnotherContext = TRUE; 68 | if (cmdOptionExists(argv, argv + argc, L"--no-context")) 69 | { 70 | checkAnotherContext = FALSE; 71 | } 72 | 73 | BOOL checkCreate = TRUE; 74 | if (cmdOptionExists(argv, argv + argc, L"--no-create")) 75 | { 76 | checkCreate = FALSE; 77 | } 78 | 79 | if (AddVectoredExceptionHandler(1, MyVectoredExceptionHandler) == nullptr) 80 | { 81 | std::wcout << L"[-] Failed to add the exception handler!" << std::endl; 82 | return 1; 83 | } 84 | 85 | std::vector clsidList; 86 | if (targetClsid.empty()) 87 | { 88 | std::wcout << L"[+] Analyzing all CLSIDs" << std::endl; 89 | clsidList = EnumerateCLSID(); 90 | } 91 | else 92 | { 93 | std::wcout << L"[+] Analyzing CLSID: " << targetClsid << std::endl; 94 | clsidList.push_back(targetClsid); 95 | } 96 | 97 | CoInitialize(NULL); 98 | std::wcout << "[+] Total CLSID: " << clsidList.size() << std::endl; 99 | 100 | auto it = clsidList.begin(); 101 | if (!startFromClsid.empty()) { 102 | it = std::find(clsidList.begin(), clsidList.end(), startFromClsid); 103 | if (it == clsidList.end()) { 104 | std::wcerr << L"[-] Specified CLSID not found in the list: " << startFromClsid << std::endl; 105 | return 1; 106 | } 107 | else 108 | { 109 | ++it; // --from + 1 110 | } 111 | } 112 | 113 | for (; it != clsidList.end(); it++) 114 | { 115 | AnalyzeCLSID(*it, checkCreate, checkAnotherContext); 116 | } 117 | 118 | CoUninitialize(); 119 | 120 | return 0; 121 | } -------------------------------------------------------------------------------- /ComDiver/COMDiver/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include -------------------------------------------------------------------------------- /ComDiver/x64/Debug/ComDiver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/ComDiver/x64/Debug/ComDiver.exe -------------------------------------------------------------------------------- /ComDiver/x64/Debug/ComDiver.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/ComDiver/x64/Debug/ComDiver.pdb -------------------------------------------------------------------------------- /ComTraveller/ComTraveller.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34009.444 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ComTraveller", "ComTraveller\ComTraveller.vcxproj", "{87C00375-9918-4779-8458-3E77864BCC57}" 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 | {87C00375-9918-4779-8458-3E77864BCC57}.Debug|x64.ActiveCfg = Debug|x64 17 | {87C00375-9918-4779-8458-3E77864BCC57}.Debug|x64.Build.0 = Debug|x64 18 | {87C00375-9918-4779-8458-3E77864BCC57}.Debug|x86.ActiveCfg = Debug|Win32 19 | {87C00375-9918-4779-8458-3E77864BCC57}.Debug|x86.Build.0 = Debug|Win32 20 | {87C00375-9918-4779-8458-3E77864BCC57}.Release|x64.ActiveCfg = Release|x64 21 | {87C00375-9918-4779-8458-3E77864BCC57}.Release|x64.Build.0 = Release|x64 22 | {87C00375-9918-4779-8458-3E77864BCC57}.Release|x86.ActiveCfg = Release|Win32 23 | {87C00375-9918-4779-8458-3E77864BCC57}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {C8AD873B-1409-40FE-9B70-0CD26930F0FA} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /ComTraveller/ComTraveller/ComTraveller.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 | 17.0 23 | Win32Proj 24 | {87c00375-9918-4779-8458-3e77864bcc57} 25 | COMHunter 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | true 77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | Console 82 | true 83 | 84 | 85 | 86 | 87 | Level3 88 | true 89 | true 90 | true 91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | true 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | Default 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | true 119 | true 120 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | 123 | 124 | Console 125 | true 126 | true 127 | true 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /ComTraveller/ComTraveller/ComTraveller.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Исходные файлы 20 | 21 | 22 | Исходные файлы 23 | 24 | 25 | 26 | 27 | Файлы заголовков 28 | 29 | 30 | Файлы заголовков 31 | 32 | 33 | -------------------------------------------------------------------------------- /ComTraveller/ComTraveller/ComTraveller.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --from {e5b35059-a1be-4977-9bee-5c44226340f7} 5 | WindowsLocalDebugger 6 | 7 | -------------------------------------------------------------------------------- /ComTraveller/ComTraveller/enumerator.cpp: -------------------------------------------------------------------------------- 1 | #include "enumerator.h" 2 | 3 | bool HasTypeLib(IDispatch* pDispatch) 4 | { 5 | CComPtr spTypeInfo; 6 | TYPEATTR* pTypeAttr = nullptr; 7 | 8 | HRESULT hr = pDispatch->GetTypeInfo(0, LOCALE_USER_DEFAULT, &spTypeInfo); 9 | if (FAILED(hr)) 10 | { 11 | //std::wcout << L"Failed to get type info." << std::endl; 12 | return FALSE; 13 | } 14 | 15 | hr = spTypeInfo->GetTypeAttr(&pTypeAttr); 16 | if (FAILED(hr)) 17 | { 18 | // std::wcout << L"Failed to get type attributes." << std::endl; 19 | return FALSE; 20 | } 21 | 22 | return TRUE; 23 | } 24 | 25 | 26 | HRESULT CoCreateInstanceInSession(DWORD session, REFCLSID rclsid, REFIID riid, void** ppv) 27 | { 28 | BIND_OPTS3 bo = {}; 29 | WCHAR wszCLSID[50]; 30 | WCHAR wszMonikerName[300]; 31 | StringFromGUID2(rclsid, wszCLSID, _countof(wszCLSID)); 32 | StringCchPrintf(wszMonikerName, _countof(wszMonikerName), 33 | L"session:%d!new:%s", session, wszCLSID); 34 | bo.cbStruct = sizeof(bo); 35 | bo.dwClassContext = CLSCTX_LOCAL_SERVER; 36 | return CoGetObject(wszMonikerName, &bo, riid, ppv); 37 | } 38 | 39 | std::vector EnumerateCLSID() 40 | { 41 | std::vector clsidList; 42 | HKEY hKey; 43 | LONG nError; 44 | 45 | nError = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"CLSID", 0, KEY_READ, &hKey); 46 | if (nError == ERROR_SUCCESS) 47 | { 48 | DWORD dwIndex = 0; 49 | WCHAR szName[MAX_PATH]; 50 | DWORD dwNameSize = _countof(szName); 51 | FILETIME ftLastWriteTime; 52 | 53 | while (RegEnumKeyEx(hKey, dwIndex, szName, &dwNameSize, NULL, NULL, NULL, &ftLastWriteTime) == ERROR_SUCCESS) 54 | { 55 | clsidList.push_back(szName); 56 | dwNameSize = _countof(szName); 57 | dwIndex++; 58 | } 59 | 60 | RegCloseKey(hKey); 61 | } 62 | else 63 | { 64 | std::wcerr << L"Cant open HKEY_CLASSES_ROOT\\CLSID. Error: " << nError << std::endl; 65 | } 66 | 67 | return clsidList; 68 | } 69 | 70 | DWORD GetAppIdFromClsid(IN std::wstring clsid, OUT std::wstring& appId) 71 | { 72 | HKEY hClsidKey; 73 | std::wstring clsidSubKey = L"CLSID\\" + clsid; 74 | if (RegOpenKeyEx(HKEY_CLASSES_ROOT, clsidSubKey.c_str(), 0, KEY_READ, &hClsidKey) != ERROR_SUCCESS) 75 | { 76 | return ERROR_OPEN_FAILED; 77 | } 78 | 79 | TCHAR valueBuffer[256]; 80 | DWORD valueBufferSize = sizeof(valueBuffer); 81 | 82 | if (RegQueryValueEx(hClsidKey, L"AppID", NULL, NULL, (LPBYTE)valueBuffer, &valueBufferSize) == ERROR_SUCCESS) 83 | { 84 | appId = valueBuffer; 85 | } 86 | 87 | RegCloseKey(hClsidKey); 88 | 89 | return ERROR_SUCCESS; 90 | } 91 | 92 | DWORD GetProgIdFromClsid(IN std::wstring clsid, OUT std::wstring& progId) 93 | { 94 | HKEY hKey; 95 | if (RegOpenKeyEx(HKEY_CLASSES_ROOT, NULL, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 96 | { 97 | return ERROR_OPEN_FAILED; 98 | } 99 | 100 | DWORD index = 0; 101 | TCHAR subKeyName[256]; 102 | DWORD subKeyNameSize = sizeof(subKeyName) / sizeof(subKeyName[0]); 103 | LONG ret = ERROR_SUCCESS; 104 | 105 | while ((ret = RegEnumKeyEx(hKey, index, subKeyName, &subKeyNameSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS) 106 | { 107 | HKEY hSubKey; 108 | 109 | if (RegOpenKeyEx(hKey, subKeyName, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) 110 | { 111 | DWORD valueBufferSize = 0; 112 | if (RegQueryValueEx(hSubKey, L"CLSID", NULL, NULL, NULL, &valueBufferSize) == ERROR_SUCCESS) 113 | { 114 | TCHAR* valueBuffer = new TCHAR[valueBufferSize / sizeof(TCHAR)]; 115 | if (RegQueryValueEx(hSubKey, L"CLSID", NULL, NULL, (LPBYTE)valueBuffer, &valueBufferSize) == ERROR_SUCCESS) 116 | { 117 | if (clsid == valueBuffer) 118 | { 119 | progId = subKeyName; 120 | delete[] valueBuffer; 121 | RegCloseKey(hSubKey); 122 | RegCloseKey(hKey); 123 | return ERROR_SUCCESS; 124 | } 125 | } 126 | delete[] valueBuffer; 127 | } 128 | RegCloseKey(hSubKey); 129 | } 130 | 131 | subKeyNameSize = sizeof(subKeyName) / sizeof(subKeyName[0]); 132 | index++; 133 | } 134 | 135 | RegCloseKey(hKey); 136 | return ERROR_NOT_FOUND; 137 | } 138 | 139 | DWORD GetRunAsKeyFromAppId(IN std::wstring appId, OUT std::wstring& runAs) 140 | { 141 | std::wstring appIdSubKey = L"AppID\\" + appId; 142 | HKEY hAppIdKey; 143 | if (RegOpenKeyEx(HKEY_CLASSES_ROOT, appIdSubKey.c_str(), 0, KEY_READ, &hAppIdKey) == ERROR_SUCCESS) 144 | { 145 | DWORD valueBufferSize = 256; 146 | TCHAR* valueBuffer = new TCHAR[valueBufferSize / sizeof(TCHAR)]; 147 | if (RegQueryValueEx(hAppIdKey, L"RunAs", NULL, NULL, (LPBYTE)valueBuffer, &valueBufferSize) == ERROR_SUCCESS) 148 | { 149 | runAs = valueBuffer; 150 | return ERROR_SUCCESS; 151 | } 152 | RegCloseKey(hAppIdKey); 153 | } 154 | return ERROR_OBJECT_NOT_FOUND; 155 | } 156 | 157 | std::wstring GetUserNameFromSID(PSID sid) 158 | { 159 | WCHAR name[256]; 160 | WCHAR domain[256]; 161 | DWORD nameSize = sizeof(name) / sizeof(WCHAR); 162 | DWORD domainSize = sizeof(domain) / sizeof(WCHAR); 163 | SID_NAME_USE sidUse; 164 | 165 | if (!LookupAccountSid(NULL, sid, name, &nameSize, domain, &domainSize, &sidUse)) 166 | return L""; 167 | 168 | std::wstring fullName(domain); 169 | fullName += L"\\\\"; 170 | fullName += name; 171 | 172 | return fullName; 173 | } 174 | 175 | std::wstring GetProcessUserName(DWORD pid) 176 | { 177 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); 178 | if (!hProcess) 179 | return L""; 180 | 181 | HANDLE hToken; 182 | if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) 183 | { 184 | CloseHandle(hProcess); 185 | return L""; 186 | } 187 | 188 | DWORD bufferSize = 0; 189 | GetTokenInformation(hToken, TokenUser, NULL, 0, &bufferSize); 190 | 191 | if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 192 | { 193 | CloseHandle(hToken); 194 | CloseHandle(hProcess); 195 | return L""; 196 | } 197 | 198 | std::vector buffer(bufferSize); 199 | if (!GetTokenInformation(hToken, TokenUser, buffer.data(), bufferSize, &bufferSize)) 200 | { 201 | CloseHandle(hToken); 202 | CloseHandle(hProcess); 203 | return L""; 204 | } 205 | 206 | PSID sid = reinterpret_cast(buffer.data())->User.Sid; 207 | std::wstring userName = GetUserNameFromSID(sid); 208 | 209 | CloseHandle(hToken); 210 | CloseHandle(hProcess); 211 | 212 | return userName; 213 | } 214 | 215 | BOOL GetPIDFromIUnknown(IN IUnknown* pUnknown, OUT DWORD* pid) 216 | { 217 | CComPtr marshalStream; 218 | CreateStreamOnHGlobal(NULL, TRUE, &marshalStream); 219 | 220 | CoMarshalInterface( 221 | marshalStream, 222 | IID_IUnknown, 223 | pUnknown, 224 | MSHCTX_INPROC, 225 | NULL, 226 | MSHLFLAGS_NORMAL 227 | ); 228 | 229 | HGLOBAL memoryHandleFromStream = NULL; 230 | GetHGlobalFromStream(marshalStream, &memoryHandleFromStream); 231 | 232 | LPOBJREF objref = reinterpret_cast (GlobalLock(memoryHandleFromStream)); 233 | if (objref && objref->signature == OBJREF_SIGNATURE) 234 | { 235 | IPID ipid; 236 | 237 | if (objref->flags == OBJREF_STANDARD) 238 | { 239 | ipid = objref->u_objref.u_standard.std.ipid; 240 | } 241 | else if (objref->flags == OBJREF_HANDLER) 242 | { 243 | ipid = objref->u_objref.u_handler.std.ipid; 244 | } 245 | else if (objref->flags == OBJREF_EXTENDED) 246 | { 247 | ipid = objref->u_objref.u_extended.std.ipid; 248 | } 249 | else if (objref->flags == OBJREF_CUSTOM) 250 | { 251 | return FALSE; 252 | } 253 | 254 | static const int COM_SERVER_PID_OFFSET = 4; 255 | 256 | *pid = *reinterpret_cast( 257 | (reinterpret_cast(&ipid) + COM_SERVER_PID_OFFSET) 258 | ); 259 | return *pid != 0xffff; 260 | } 261 | } 262 | 263 | std::wstring GetProcessName(DWORD processID) { 264 | std::wstring processName = L""; 265 | 266 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); 267 | 268 | if (NULL != hProcess) { 269 | HMODULE hMod; 270 | DWORD cbNeeded; 271 | 272 | if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) { 273 | wchar_t szProcessName[MAX_PATH]; 274 | if (GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName) / sizeof(wchar_t))) { 275 | processName = szProcessName; 276 | } 277 | } 278 | else 279 | { 280 | std::wcout << L"[-] EnumProcessModules() Failed: " << GetLastError() << std::endl; 281 | } 282 | 283 | CloseHandle(hProcess); 284 | } 285 | 286 | return processName; 287 | } 288 | -------------------------------------------------------------------------------- /ComTraveller/ComTraveller/enumerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | HRESULT CoCreateInstanceInSession(DWORD session, REFCLSID rclsid, REFIID riid, void** ppv); 12 | bool HasTypeLib(IDispatch* pDispatch); 13 | std::vector EnumerateCLSID(); 14 | DWORD GetAppIdFromClsid(IN std::wstring clsid, OUT std::wstring& appId); 15 | DWORD GetProgIdFromClsid(IN std::wstring clsid, OUT std::wstring& progId); 16 | DWORD GetRunAsKeyFromAppId(IN std::wstring appId, OUT std::wstring& runAs); 17 | BOOL GetPIDFromIUnknown(IN IUnknown* pUnknown, OUT DWORD* pid); 18 | std::wstring GetProcessUserName(DWORD pid); 19 | std::wstring GetProcessName(DWORD processID); 20 | 21 | typedef struct tagDATAELEMENT 22 | { 23 | GUID dataID; 24 | unsigned long cbSize; 25 | unsigned long cbRounded; 26 | /* [size_is] */ BYTE Data[1]; 27 | } DATAELEMENT; 28 | 29 | typedef struct tagDUALSTRINGARRAY 30 | { 31 | unsigned short wNumEntries; 32 | unsigned short wSecurityOffset; 33 | /* [size_is] */ unsigned short aStringArray[1]; 34 | } DUALSTRINGARRAY; 35 | 36 | typedef unsigned __int64 OXID; 37 | typedef unsigned __int64 OID; 38 | typedef GUID IPID; 39 | 40 | typedef struct tagOBJREFDATA 41 | { 42 | unsigned long nElms; 43 | /* [unique][size_is][size_is] */ DATAELEMENT** ppElmArray; 44 | } OBJREFDATA; 45 | 46 | typedef struct tagSTDOBJREF { 47 | unsigned long flags; 48 | unsigned long cPublicRefs; 49 | OXID oxid; 50 | OID oid; 51 | IPID ipid; 52 | } STDOBJREF; 53 | 54 | typedef struct tagOBJREF { 55 | unsigned long signature; 56 | unsigned long flags; 57 | GUID iid; 58 | union { 59 | struct { 60 | STDOBJREF std; 61 | DUALSTRINGARRAY saResAddr; 62 | } u_standard; 63 | struct { 64 | STDOBJREF std; 65 | CLSID clsid; 66 | DUALSTRINGARRAY saResAddr; 67 | } u_handler; 68 | struct { 69 | CLSID clsid; 70 | unsigned long cbExtension; 71 | unsigned long size; 72 | byte* pData; 73 | } u_custom; 74 | struct { 75 | STDOBJREF std; 76 | unsigned long Signature1; 77 | DUALSTRINGARRAY saResAddr; 78 | unsigned long nElms; 79 | unsigned long Signature2; 80 | DATAELEMENT ElmArray; 81 | } u_extended; 82 | } u_objref; 83 | } OBJREF, * LPOBJREF; 84 | 85 | typedef struct _IPID_ENTRY { 86 | IID iid; 87 | IPID ipid; // IPID to bind to 88 | OXID oxid; // Object Exporter ID 89 | OID oid; 90 | } IPID_ENTRY, * PIPID_ENTRY; 91 | 92 | 93 | #define OBJREF_SIGNATURE ( 0x574f454d ) 94 | 95 | #define OBJREF_STANDARD ( 0x1 ) 96 | #define OBJREF_HANDLER ( 0x2 ) 97 | #define OBJREF_CUSTOM ( 0x4 ) 98 | #define OBJREF_EXTENDED ( 0x8 ) -------------------------------------------------------------------------------- /ComTraveller/ComTraveller/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | 4 | LONG WINAPI MyVectoredExceptionHandler(PEXCEPTION_POINTERS exceptionInfo) 5 | { 6 | std::wcout << L"\t[!] Exception occurred!" << std::endl; 7 | 8 | std::wcout << L"\t[!] Exception Code: " << exceptionInfo->ExceptionRecord->ExceptionCode << std::endl; 9 | std::wcout << L"\t[!] Exception Address: " << exceptionInfo->ExceptionRecord->ExceptionAddress << std::endl; 10 | 11 | std::wcout << L"\t[!!!] If program had crashed pls restart using .\\COMHunter.exe --from " << std::endl; 12 | 13 | return EXCEPTION_EXECUTE_HANDLER; 14 | } 15 | 16 | void WriteDataToCSV(HANDLE hFile, const std::vector& row) 17 | { 18 | SetFilePointer(hFile, 0, NULL, FILE_END); 19 | bool first = true; 20 | for (const auto& cell : row) 21 | { 22 | if (!first) 23 | { 24 | WCHAR comma = L','; 25 | DWORD bytesWritten; 26 | WriteFile(hFile, &comma, sizeof(comma), &bytesWritten, NULL); 27 | } 28 | else 29 | { 30 | first = false; 31 | } 32 | 33 | DWORD bytesWritten; 34 | WriteFile(hFile, cell.c_str(), cell.size() * sizeof(WCHAR), &bytesWritten, NULL); 35 | } 36 | 37 | WCHAR newline = L'\n'; 38 | DWORD bytesWritten; 39 | WriteFile(hFile, &newline, sizeof(newline), &bytesWritten, NULL); 40 | } 41 | 42 | std::wstring FormatHResult(HRESULT hr) { 43 | std::wstringstream ss; 44 | ss << L"- Err: 0x" << std::hex << hr; 45 | 46 | if (HRESULT_FACILITY(hr) == FACILITY_WIN32) { 47 | hr = HRESULT_CODE(hr); 48 | } 49 | 50 | LPWSTR errorMsg = nullptr; 51 | DWORD size = FormatMessage( 52 | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 53 | nullptr, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 54 | (LPWSTR)&errorMsg, 0, nullptr); 55 | 56 | std::wstring errorDesc = (size != 0 && errorMsg != nullptr) ? errorMsg : L"Unknown Error"; 57 | if (errorMsg) { 58 | LocalFree(errorMsg); 59 | } 60 | 61 | if (!errorDesc.empty() && errorDesc.back() == L'\n') { 62 | errorDesc.pop_back(); 63 | } 64 | 65 | return ss.str() + L" " + errorDesc; 66 | } 67 | 68 | bool IsBlacklisted(const std::wstring& clsid, const std::vector& blackList) 69 | { 70 | std::wstring clsidLower = clsid; 71 | 72 | std::transform(clsidLower.begin(), clsidLower.end(), clsidLower.begin(), ::towlower); 73 | 74 | for (const auto& blacklistedClsid : blackList) { 75 | std::wstring blacklistedClsidLower = blacklistedClsid; 76 | std::transform(blacklistedClsidLower.begin(), blacklistedClsidLower.end(), blacklistedClsidLower.begin(), ::towlower); 77 | 78 | if (clsidLower == blacklistedClsidLower) { 79 | return true; 80 | } 81 | } 82 | 83 | return false; 84 | } 85 | 86 | 87 | void ShowHelp() 88 | { 89 | std::cout << R"( 90 | ,,_ 91 | zd$$??= 92 | z$$P? F:`c, _ 93 | d$$, `c'cc$$i ,cd$?R 94 | $$$$ cud$,?$$$i ,=P"2?z " 95 | $" " ?$$$,?$$$. ,-''`>, bzP 96 | 'cLdb,?$$,?$$$ ,h' "I$'J$P 97 | ... `?$$$,"$$,`$$h $$PxrF'd$" 98 | d$PP""?-,"?$$,?$h`$$,,$$'$F44" 99 | ?,,_`=4c,?=,"?hu?$`?L4$'? ' 100 | `""?==""=-"" `""-`'_,,,, 101 | .ccu?m?e?JC,-,"=? 102 | """=='?" 103 | )" << std::endl; 104 | std::wcout << L"ComTraveller - small tool to parse and extract information about all registered CLSIDs on the system" << std::endl; 105 | std::wcout << L"Usage: " << std::endl; 106 | std::wcout << L"--file - output filename. Default: output.csv" << std::endl; 107 | std::wcout << L"--from - start exploring clsids from this clsid. (for ex. default enum from 1 to 9. with --from 4 will be from 4 to 9)" << std::endl; 108 | std::wcout << L"--session - use if you want to check Cross-Session Activation in a specific session. Useful only with 'Run as interactive user COM objects'" << std::endl; 109 | std::wcout << L"--target - analyze this CLSID" << std::endl; 110 | std::wcout << L"-h/--help - shows this screen" << std::endl; 111 | } 112 | 113 | int wmain(int argc, wchar_t* argv[]) 114 | { 115 | setlocale(LC_ALL, ""); 116 | std::wstring startFromCLSID; 117 | std::wstring targetCLSID; 118 | std::wstring outputFilename = L"output.csv"; 119 | DWORD session = 0; 120 | 121 | for (int i = 1; i < argc; i++) { 122 | if (std::wstring(argv[i]) == L"--from" && i + 1 < argc) { 123 | startFromCLSID = argv[i + 1]; 124 | } 125 | else if (std::wstring(argv[i]) == L"--file" && i + 1 < argc) { 126 | outputFilename = argv[i + 1]; 127 | } 128 | else if (std::wstring(argv[i]) == L"--session" && i + 1 < argc) { 129 | session = _wtoi(argv[i + 1]); 130 | } 131 | else if (std::wstring(argv[i]) == L"--target" && i + 1 < argc) 132 | { 133 | targetCLSID = argv[i + 1]; 134 | } 135 | else if (((std::wstring(argv[i]) == L"-h") || (std::wstring(argv[i]) == L"--help"))) 136 | { 137 | ShowHelp(); 138 | return 0; 139 | } 140 | } 141 | 142 | std::wcout << L"[COM Traveller] Starting......." << std::endl; 143 | std::wcout << L"[COM Traveller] Params:" << std::endl; 144 | std::wcout << L"[Initial CLSID. Empty -> not specified] " << startFromCLSID << std::endl; 145 | std::wcout << L"[Target CLSID. Empty -> not specified] " << targetCLSID << std::endl; 146 | std::wcout << L"[Output FileName] " << outputFilename << std::endl; 147 | std::wcout << L"[Activate in session. 0 -> dont checking] " << session << std::endl; 148 | Sleep(1000); 149 | 150 | HANDLE hFile = CreateFileW( 151 | outputFilename.c_str(), 152 | FILE_APPEND_DATA | GENERIC_WRITE, 153 | 0, 154 | NULL, 155 | OPEN_ALWAYS, 156 | FILE_ATTRIBUTE_NORMAL, 157 | NULL 158 | ); 159 | 160 | if (hFile == INVALID_HANDLE_VALUE) 161 | { 162 | std::wcerr << L"[-] Can't open file " << outputFilename << L" for writing" << std::endl; 163 | return 1; 164 | } 165 | 166 | DWORD fileSize = GetFileSize(hFile, NULL); 167 | if (fileSize == INVALID_FILE_SIZE) 168 | { 169 | std::wcerr << L"[-] Can't get file size for " << outputFilename << std::endl; 170 | CloseHandle(hFile); 171 | return 1; 172 | } 173 | 174 | WCHAR bom = 0xFEFF; // UTF-16-LE BOM Header 175 | DWORD bytesWritten; 176 | WriteFile(hFile, &bom, sizeof(bom), &bytesWritten, NULL); 177 | 178 | if (AddVectoredExceptionHandler(1, MyVectoredExceptionHandler) == nullptr) 179 | { 180 | std::wcout << L"[-] Failed to add the exception handler!" << std::endl; 181 | return 1; 182 | } 183 | 184 | CoInitialize(NULL); 185 | 186 | std::vector clsidList; 187 | if (targetCLSID.empty()) 188 | { 189 | clsidList = EnumerateCLSID(); 190 | } 191 | else 192 | { 193 | clsidList.push_back(targetCLSID); 194 | } 195 | 196 | std::vector clsidBlackList; 197 | 198 | // WIN10 Optional 199 | /* 200 | std::vector clsidBlackList = 201 | { 202 | L"CLSID", 203 | L"{00B01B2E-B1FE-33A6-AD40-57DE8358DC7D}", 204 | L"{0A14D3FF-EC53-450f-AA30-FFBC55BE26A2}", 205 | L"{010911E2-F61C-479B-B08C-43E6D1299EFE}", 206 | L"{1b7cd997-e5ff-4932-a7a6-2a9e636da385}", 207 | L"{0B30F034-02D5-4E2B-9BB7-A9F6538F4110}", 208 | L"{1123D0C1-886C-42C3-98E6-7109780E8BE2}", 209 | L"{1910E202-236A-43E6-9469-FE0B3149F3D9}", 210 | L"{1b283861-754f-4022-ad47-a5eaaa618894}", 211 | L"{1b7cd997-e5ff-4932-a7a6-2a9e636da385}", 212 | L"{1ee7337f-85ac-45e2-a23c-37c753209769}", 213 | L"{1F87137D-0E7C-44d5-8C73-4EFFB68962F2}", 214 | L"{1FA9085F-25A2-489B-85D4-86326EEDCD87}", 215 | L"{23F6D342-08C4-4E48-89B3-0BC8BF990783}", 216 | L"{265b1075-d22b-41eb-bc97-87568f3e6dab}", 217 | L"{2DCD7FDB-8809-48E4-8E4F-3157C57CF987}", 218 | L"{2F21A1B8-750B-4AC7-A6E2-C70A3F2D21FB}", 219 | L"{31337EC7-5767-11CF-BEAB-00AA006C3606}", 220 | L"{34684F0B-6721-4DC5-AF04-A8C2C1C3609}", 221 | L"{34684F0B-6721-4DC5-AF04-A8C2C1C3609E}", 222 | L"{36BAA497-8C84-4700-96A1-88E1876EC5B9}", 223 | L"{337448ee-2a70-43f7-99f9-40f2857950b9}", // Crashes program 224 | L"{4032FE99-EA88-432C-B870-D975C9F1D5F9}", 225 | L"{41945702-8302-44A6-9445-AC98E8AFA086}", 226 | L"{454CBB06-6BDE-4F0D-8392-C4BCE2A0B71B}", 227 | L"{45BA127D-10A8-46EA-8AB7-56EA9078943C}", 228 | L"{4575438F-A6C8-4976-B0FE-2F26B80D959E}", 229 | L"{4729dc2b-36ff-405f-bd36-f45113adb052}", // Crashes program 230 | L"{49E6370B-AB71-40AB-92F4-B009593E4518}", 231 | L"{4A56AF32-C21F-11DB-96FA-005056C00008}", // Crashes program 232 | L"{4B601364-A04B-38BC-BD38-A18E981324CF}", 233 | L"{4C1D33D1-3161-4A76-9487-2677CD589C11}", 234 | L"{50FDBB99-5C92-495E-9E81-E2C2F48CDDAE}", 235 | L"{55200BC1-D537-44E2-BC6B-DD098A015FA1}", 236 | L"{63766597-1825-407D-8752-098F33846F46}", // Killing output 237 | L"{6850404F-D7FB-32BD-8328-C94F66E8C1C7}", 238 | L"{69F9CB25-25E2-4BE1-AB8F-07AA7CB535E8}", 239 | L"{6ACB028E-48C0-4A44-964C-E14567C578BA}", 240 | L"{6C3EE638-B588-4D7D-B30A-E7E36759305D}", 241 | L"{73AD6842-ACE0-45E8-A4DD-8795881A2C2A}", 242 | L"{749962AB-D849-46D5-A39C-75A8307C2C86}", 243 | L"{7724F5B4-9A4A-4a93-AD09-B06F7AB31035}", 244 | L"{78D22140-40CF-303E-BE96-B3AC0407A34D}", 245 | L"{8A99553A-7971-4445-93B5-AAA43D1433C5}", 246 | L"{95243A62-2F9B-4FDF-B437-40D965F6D17F}", // Crashes program 247 | L"{99B29D3B-368A-4BE6-B675-805A69114497}", // Crashes program 248 | L"{9A3A64F4-8BA5-3DCF-880C-8D3EE06C5538}", 249 | L"{9B78F0E6-3E05-4A5B-B2E8-E743A8956B65}", 250 | L"{9B97D384-048C-4e24-926D-DB6F0841C9E4}", 251 | L"{9BA05972-F6A8-11CF-A442-00A0C90A8F39}", 252 | L"{9BF8D948-5C56-450e-BAF8-D6144C6E81CB}", 253 | L"{9c15e692-86da-4ab8-8b5e-6ac79deb6f20}", 254 | L"{9C24A977-0951-451A-8006-0E49BD28CD5F}", 255 | L"{9C49FB9B-4E8C-43AE-BACF-76404B422264}", 256 | L"{9C4D3346-650D-472d-A867-6F595B39D973}", 257 | L"{9C67F424-22DC-3D05-AB36-17EAF95881F2}", 258 | L"{9C695035-48D2-4229-8B73-4C70E756E519}", 259 | L"{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}", 260 | L"{9C86F320-DEE3-4DD1-B972-A303F26B061E}", 261 | L"{9c8db22b-8ddc-471c-9628-48847514b424}", 262 | L"{9CAB4470-D6FA-4903-986C-7D5A755B2691}", 263 | L"{9caf4a2e-c957-48c7-b4d2-4d11188e0b94}", 264 | L"{9cb233a5-a4a5-46b9-ab13-db07ce949410}", 265 | L"{9CB5172B-D600-46BA-AB77-77BB7E3A00D9}", 266 | L"{9CB89EFF-B39E-4D5C-A493-F2171580CC21}", 267 | L"{9cca66bb-9c78-4e59-a76f-a5e9990b8aa0}", 268 | L"{9CD64701-BDF3-4D14-8E03-F12983D86664}", 269 | L"{9cfc2df3-6ba3-46ef-a836-e519e81f0ec4}", 270 | L"{9d06f027-cbfc-421a-97b3-f09a8a9359bc}", 271 | L"{9D148290-B9C8-11D0-A4CC-0000F80149F6}", 272 | L"{9DAC2C1E-7C5C-40eb-833B-323E85A1CE84}", 273 | L"{A0F8D82C-E4D8-4ED9-BD3A-867A830B12BA}", 274 | L"{AA75448A-2459-4C8C-A801-3C98D7CA3D45}", 275 | L"{A7C452EF-8E9F-42EB-9F2B-245613CA0DC9}", 276 | L"{A961F842-FC8E-4D53-8074-4AB67E8854B4}", 277 | L"{BA126ADF-2166-11D1-B1D0-00805FC1270E}", 278 | L"{c39b7f77-976c-4983-b888-dbdc948d5364}", // Crashes program 279 | L"{CC6D9715-F553-4299-B2CE-6C7851FAA03A}", 280 | L"{ecabafc0-7f19-11d2-978e-0000f8757e2a}", 281 | L"{e5b35059-a1be-4977-9bee-5c44226340f7}", 282 | L"{EDA59C23-FCB4-44AF-BFE0-3708C08A212D}", 283 | L"{E0BA3BF5-25EF-459F-9EE0-855FD3666692}", 284 | L"{FFE8C349-2BB1-411F-93CE-0364C5F9FD9F}" 285 | }; // WIN10 Enterprise 286 | */ 287 | std::wcout << "[+] Total CLSID: " << clsidList.size() << std::endl; 288 | 289 | std::vector> data; 290 | 291 | if (fileSize == 0) { 292 | data.push_back({ L"CLSID", L"AppID", L"ProgID", L"RunAs", L"Username", L"PID", L"ProcessName", L"HasTypeLib", L"canCrossSessionActivate"}); 293 | 294 | WriteDataToCSV(hFile, data.back()); 295 | } 296 | 297 | auto it = clsidList.begin(); 298 | if (!startFromCLSID.empty()) { 299 | it = std::find(clsidList.begin(), clsidList.end(), startFromCLSID); 300 | if (it == clsidList.end()) { 301 | std::wcerr << L"[-] Specified CLSID not found in the list: " << startFromCLSID << std::endl; 302 | return 1; 303 | } 304 | else 305 | { 306 | ++it; // --from + 1 307 | } 308 | } 309 | 310 | for (; it != clsidList.end(); ++it) 311 | { 312 | const auto& wsclsid = *it; 313 | 314 | std::wcout << L"----------------------------" << std::endl; 315 | std::wcout << L"----[" << wsclsid << L"]----" << std::endl; 316 | 317 | std::wstring appId = L""; 318 | std::wstring progId = L""; 319 | std::wstring runAs = L""; 320 | std::wstring username = L""; 321 | std::wstring processName = L""; 322 | std::wstring hasTypeLib = L"-"; 323 | std::wstring canCrossSessionActivate = L"?"; 324 | DWORD pid = 0; 325 | 326 | if (GetAppIdFromClsid(wsclsid, appId) != ERROR_SUCCESS) 327 | { 328 | std::wcout << L"\t[-] Error in getting AppId info about CLSID: " << wsclsid << std::endl; 329 | } 330 | 331 | if (GetProgIdFromClsid(wsclsid, progId) != ERROR_SUCCESS) 332 | { 333 | std::wcout << L"\t[-] Error in getting ProgId info about CLSID: " << wsclsid << std::endl; 334 | } 335 | 336 | if (!appId.empty()) 337 | { 338 | if (GetRunAsKeyFromAppId(appId, runAs) != ERROR_SUCCESS) 339 | { 340 | std::wcout << L"\t[-] Error getting runas for AppId: " << appId << std::endl; 341 | } 342 | } 343 | 344 | HRESULT hr; 345 | CComPtr pUnknown = nullptr; 346 | 347 | CLSID clsid; 348 | 349 | hr = CLSIDFromString(wsclsid.c_str(), &clsid); 350 | if (!SUCCEEDED(hr)) 351 | { 352 | std::wcout << L"\t[-] Error in converting " << wsclsid << L" to CLSID" << std::endl; 353 | continue; 354 | } 355 | 356 | if (IsBlacklisted(wsclsid, clsidBlackList)) 357 | { 358 | std::wcout << L"\t[!] Found blacklisted clsid. Skipping" << std::endl; 359 | continue; 360 | } 361 | 362 | std::wcout << L"\t[?] Trying to start CLSID: " << wsclsid << std::endl; 363 | 364 | hr = CoCreateInstance(clsid, 365 | nullptr, 366 | CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, 367 | IID_IUnknown, 368 | reinterpret_cast(&pUnknown)); 369 | 370 | if (!SUCCEEDED(hr)) 371 | { 372 | std::wcout << L"\t[-] Error in CoCreateInstance: " << hr << L" CLSID: " << wsclsid << std::endl; 373 | continue; 374 | } 375 | 376 | std::wcout << L"\t[+] Creation success " << wsclsid << std::endl; 377 | 378 | CComPtr pDispatch; 379 | hr = pUnknown->QueryInterface(IID_IDispatch, (void**)&pDispatch); 380 | if (SUCCEEDED(hr)) 381 | { 382 | if (HasTypeLib(pDispatch)) 383 | { 384 | hasTypeLib = L"+"; 385 | } 386 | } 387 | 388 | if (GetPIDFromIUnknown(pUnknown, &pid) != TRUE) 389 | { 390 | std::wcout << L"\t[-] Can't get PID from clsid: " << wsclsid << std::endl; 391 | } 392 | 393 | if (pid != 0) 394 | { 395 | std::wcout << L"\t[+] PID: " << pid << std::endl; 396 | processName = GetProcessName(pid); 397 | std::wcout << L"\t[+] Process: " << processName << std::endl; 398 | username = GetProcessUserName(pid); 399 | std::wcout << L"\t[+] Username: " << username << std::endl; 400 | } 401 | 402 | if (session != 0) 403 | { 404 | canCrossSessionActivate = L"-"; 405 | 406 | CComPtr pUnkCross; 407 | HRESULT hr = CoCreateInstanceInSession(session, clsid, IID_IUnknown, (void**)&pUnkCross); 408 | switch (hr) 409 | { 410 | case S_OK: 411 | canCrossSessionActivate = L"+"; 412 | break; 413 | default: 414 | canCrossSessionActivate = FormatHResult(hr); 415 | } 416 | } 417 | 418 | std::wcout << L"\t[+] AppID: " << appId << std::endl; 419 | std::wcout << L"\t[+] RunAs: " << runAs << std::endl; 420 | std::wcout << L"\t[+] HasTypeLib: " << hasTypeLib << std::endl; 421 | std::wcout << L"\t[+] Cross Session: " << canCrossSessionActivate << std::endl; 422 | 423 | data.push_back({ std::wstring(wsclsid.begin(), wsclsid.end()), 424 | std::wstring(appId.begin(), appId.end()), 425 | std::wstring(progId.begin(), progId.end()), 426 | std::wstring(runAs.begin(), runAs.end()), 427 | std::wstring(username.begin(), username.end()), 428 | std::to_wstring(pid), 429 | std::wstring(processName.begin(), processName.end()), 430 | std::wstring(hasTypeLib.begin(), hasTypeLib.end()), 431 | std::wstring(canCrossSessionActivate.begin(), canCrossSessionActivate.end()) 432 | }); 433 | 434 | WriteDataToCSV(hFile, data.back()); 435 | } 436 | 437 | CloseHandle(hFile); 438 | 439 | std::wcout << L"[+] Success" << std::endl; 440 | CoUninitialize(); 441 | 442 | return 0; 443 | } 444 | -------------------------------------------------------------------------------- /ComTraveller/ComTraveller/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "enumerator.h" 15 | -------------------------------------------------------------------------------- /ComTraveller/ComTraveller/x64/Debug/ComTraveller.exe.recipe: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | A:\SSD\gitrepo\COMThanasia\ComTraveller\x64\Debug\ComTraveller.exe 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ComTraveller/ComTraveller/x64/Debug/ComTraveller.vcxproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/ComTraveller/ComTraveller/x64/Debug/ComTraveller.vcxproj.FileListAbsolute.txt -------------------------------------------------------------------------------- /ComTraveller/ComTraveller/x64/Debug/vc143.idb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/ComTraveller/ComTraveller/x64/Debug/vc143.idb -------------------------------------------------------------------------------- /ComTraveller/x64/Debug/ComTraveller.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/ComTraveller/x64/Debug/ComTraveller.exe -------------------------------------------------------------------------------- /ComTraveller/x64/Debug/ComTraveller.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/ComTraveller/x64/Debug/ComTraveller.pdb -------------------------------------------------------------------------------- /ComTraveller/x64/Debug/rep.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/ComTraveller/x64/Debug/rep.csv -------------------------------------------------------------------------------- /MonikerHound/MonikerHound.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34009.444 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MonikerHound", "MonikerHound\MonikerHound.vcxproj", "{7F959595-E629-4643-AEB7-420A4C1CDE80}" 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 | {7F959595-E629-4643-AEB7-420A4C1CDE80}.Debug|x64.ActiveCfg = Debug|x64 17 | {7F959595-E629-4643-AEB7-420A4C1CDE80}.Debug|x64.Build.0 = Debug|x64 18 | {7F959595-E629-4643-AEB7-420A4C1CDE80}.Debug|x86.ActiveCfg = Debug|Win32 19 | {7F959595-E629-4643-AEB7-420A4C1CDE80}.Debug|x86.Build.0 = Debug|Win32 20 | {7F959595-E629-4643-AEB7-420A4C1CDE80}.Release|x64.ActiveCfg = Release|x64 21 | {7F959595-E629-4643-AEB7-420A4C1CDE80}.Release|x64.Build.0 = Release|x64 22 | {7F959595-E629-4643-AEB7-420A4C1CDE80}.Release|x86.ActiveCfg = Release|Win32 23 | {7F959595-E629-4643-AEB7-420A4C1CDE80}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {099B7B16-1E84-4CE0-BB18-C85267976D4A} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /MonikerHound/MonikerHound/MonikerHound.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 | 17.0 23 | Win32Proj 24 | {7f959595-e629-4643-aeb7-420a4c1cde80} 25 | MonikerHound 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | true 77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | Console 82 | true 83 | 84 | 85 | 86 | 87 | Level3 88 | true 89 | true 90 | true 91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | true 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | true 118 | true 119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /MonikerHound/MonikerHound/MonikerHound.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Исходные файлы 20 | 21 | 22 | -------------------------------------------------------------------------------- /MonikerHound/MonikerHound/MonikerHound.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /MonikerHound/MonikerHound/Source.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef struct tagDATAELEMENT 10 | { 11 | GUID dataID; 12 | unsigned long cbSize; 13 | unsigned long cbRounded; 14 | /* [size_is] */ BYTE Data[1]; 15 | } DATAELEMENT; 16 | 17 | typedef struct tagDUALSTRINGARRAY 18 | { 19 | unsigned short wNumEntries; 20 | unsigned short wSecurityOffset; 21 | /* [size_is] */ unsigned short aStringArray[1]; 22 | } DUALSTRINGARRAY; 23 | 24 | typedef unsigned __int64 OXID; 25 | typedef unsigned __int64 OID; 26 | typedef GUID IPID; 27 | 28 | typedef struct tagOBJREFDATA 29 | { 30 | unsigned long nElms; 31 | /* [unique][size_is][size_is] */ DATAELEMENT** ppElmArray; 32 | } OBJREFDATA; 33 | 34 | typedef struct tagSTDOBJREF { 35 | unsigned long flags; 36 | unsigned long cPublicRefs; 37 | OXID oxid; 38 | OID oid; 39 | IPID ipid; 40 | } STDOBJREF; 41 | 42 | typedef struct tagOBJREF { 43 | unsigned long signature; 44 | unsigned long flags; 45 | GUID iid; 46 | union { 47 | struct { 48 | STDOBJREF std; 49 | DUALSTRINGARRAY saResAddr; 50 | } u_standard; 51 | struct { 52 | STDOBJREF std; 53 | CLSID clsid; 54 | DUALSTRINGARRAY saResAddr; 55 | } u_handler; 56 | struct { 57 | CLSID clsid; 58 | unsigned long cbExtension; 59 | unsigned long size; 60 | byte* pData; 61 | } u_custom; 62 | struct { 63 | STDOBJREF std; 64 | unsigned long Signature1; 65 | DUALSTRINGARRAY saResAddr; 66 | unsigned long nElms; 67 | unsigned long Signature2; 68 | DATAELEMENT ElmArray; 69 | } u_extended; 70 | } u_objref; 71 | } OBJREF, * LPOBJREF; 72 | 73 | typedef struct _IPID_ENTRY { 74 | IID iid; 75 | IPID ipid; // IPID to bind to 76 | OXID oxid; // Object Exporter ID 77 | OID oid; 78 | } IPID_ENTRY, * PIPID_ENTRY; 79 | 80 | 81 | #define OBJREF_SIGNATURE ( 0x574f454d ) 82 | 83 | #define OBJREF_STANDARD ( 0x1 ) 84 | #define OBJREF_HANDLER ( 0x2 ) 85 | #define OBJREF_CUSTOM ( 0x4 ) 86 | #define OBJREF_EXTENDED ( 0x8 ) 87 | 88 | std::vector EnumerateCLSID() 89 | { 90 | std::vector clsidList; 91 | HKEY hKey; 92 | LONG nError; 93 | 94 | nError = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"CLSID", 0, KEY_READ, &hKey); 95 | if (nError == ERROR_SUCCESS) 96 | { 97 | DWORD dwIndex = 0; 98 | WCHAR szName[MAX_PATH]; 99 | DWORD dwNameSize = _countof(szName); 100 | FILETIME ftLastWriteTime; 101 | 102 | while (RegEnumKeyEx(hKey, dwIndex, szName, &dwNameSize, NULL, NULL, NULL, &ftLastWriteTime) == ERROR_SUCCESS) 103 | { 104 | clsidList.push_back(szName); 105 | dwNameSize = _countof(szName); 106 | dwIndex++; 107 | } 108 | 109 | RegCloseKey(hKey); 110 | } 111 | else 112 | { 113 | std::wcerr << L"Cant open HKEY_CLASSES_ROOT\\CLSID. Error: " << nError << std::endl; 114 | } 115 | 116 | return clsidList; 117 | } 118 | 119 | bool CheckRegistryValue(HKEY hKeyRoot, const std::wstring& subKey, const std::wstring& valueName, std::wstring& outValue) 120 | { 121 | HKEY hKey; 122 | if (RegOpenKeyEx(hKeyRoot, subKey.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS) 123 | { 124 | return false; 125 | } 126 | 127 | DWORD dwType = 0; 128 | DWORD dwSize = 0; 129 | if (RegQueryValueEx(hKey, valueName.c_str(), nullptr, &dwType, nullptr, &dwSize) != ERROR_SUCCESS || (dwType != REG_SZ && dwType != REG_EXPAND_SZ)) 130 | { 131 | RegCloseKey(hKey); 132 | return false; 133 | } 134 | 135 | std::wstring value(dwSize / sizeof(wchar_t), L'\0'); 136 | if (RegQueryValueEx(hKey, valueName.c_str(), nullptr, &dwType, reinterpret_cast(&value[0]), &dwSize) != ERROR_SUCCESS) 137 | { 138 | RegCloseKey(hKey); 139 | return false; 140 | } 141 | 142 | RegCloseKey(hKey); 143 | outValue.assign(value.c_str(), dwSize / sizeof(wchar_t) - 1); 144 | return true; 145 | } 146 | 147 | bool CheckRegistryDWORD(HKEY hKeyRoot, const std::wstring& subKey, const std::wstring& valueName, DWORD& outValue) 148 | { 149 | HKEY hKey; 150 | if (RegOpenKeyEx(hKeyRoot, subKey.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS) 151 | { 152 | return false; 153 | } 154 | 155 | DWORD dwType = 0; 156 | DWORD dwSize = sizeof(DWORD); 157 | if (RegQueryValueEx(hKey, valueName.c_str(), nullptr, &dwType, reinterpret_cast(&outValue), &dwSize) != ERROR_SUCCESS || dwType != REG_DWORD) 158 | { 159 | RegCloseKey(hKey); 160 | return false; 161 | } 162 | 163 | RegCloseKey(hKey); 164 | return true; 165 | } 166 | 167 | bool DoesKeyExist(HKEY hKeyRoot, const std::wstring& subKey) 168 | { 169 | HKEY hKey; 170 | if (RegOpenKeyEx(hKeyRoot, subKey.c_str(), 0, KEY_READ, &hKey) == ERROR_SUCCESS) 171 | { 172 | RegCloseKey(hKey); 173 | return true; 174 | } 175 | return false; 176 | } 177 | 178 | bool GetDefaultRegistryValue(HKEY hKeyRoot, const std::wstring& subKey, std::wstring& outValue) 179 | { 180 | return CheckRegistryValue(hKeyRoot, subKey, L"", outValue); 181 | } 182 | 183 | HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, void** ppv) 184 | { 185 | BIND_OPTS3 bo; 186 | WCHAR wszCLSID[50]; 187 | WCHAR wszMon[300]; 188 | 189 | StringFromGUID2(rclsid, wszCLSID, sizeof(wszCLSID) / sizeof(wszCLSID[0])); 190 | HRESULT hr = StringCchPrintfW(wszMon, sizeof(wszMon) / sizeof(wszMon[0]), L"Elevation:Administrator!new:%s", wszCLSID); 191 | if (FAILED(hr)) 192 | return hr; 193 | memset(&bo, 0, sizeof(bo)); 194 | bo.cbStruct = sizeof(bo); 195 | bo.hwnd = hwnd; 196 | bo.dwClassContext = CLSCTX_LOCAL_SERVER; 197 | return CoGetObject(wszMon, &bo, riid, ppv); 198 | } 199 | 200 | BOOL GetPIDFromIUnknown(IN IUnknown* pUnknown, OUT DWORD* pid) 201 | { 202 | CComPtr marshalStream; 203 | CreateStreamOnHGlobal(NULL, TRUE, &marshalStream); 204 | 205 | CoMarshalInterface( 206 | marshalStream, 207 | IID_IUnknown, 208 | pUnknown, 209 | MSHCTX_INPROC, 210 | NULL, 211 | MSHLFLAGS_NORMAL 212 | ); 213 | 214 | HGLOBAL memoryHandleFromStream = NULL; 215 | GetHGlobalFromStream(marshalStream, &memoryHandleFromStream); 216 | 217 | LPOBJREF objref = reinterpret_cast (GlobalLock(memoryHandleFromStream)); 218 | if (objref && objref->signature == OBJREF_SIGNATURE) 219 | { 220 | IPID ipid; 221 | 222 | if (objref->flags == OBJREF_STANDARD) 223 | { 224 | ipid = objref->u_objref.u_standard.std.ipid; 225 | } 226 | else if (objref->flags == OBJREF_HANDLER) 227 | { 228 | ipid = objref->u_objref.u_handler.std.ipid; 229 | } 230 | else if (objref->flags == OBJREF_EXTENDED) 231 | { 232 | ipid = objref->u_objref.u_extended.std.ipid; 233 | } 234 | else if (objref->flags == OBJREF_CUSTOM) 235 | { 236 | return FALSE; 237 | } 238 | 239 | static const int COM_SERVER_PID_OFFSET = 4; 240 | 241 | *pid = *reinterpret_cast( 242 | (reinterpret_cast(&ipid) + COM_SERVER_PID_OFFSET) 243 | ); 244 | return *pid != 0xffff; 245 | } 246 | } 247 | 248 | std::wstring GetProcessName(DWORD processID) { 249 | std::wstring processName = L""; 250 | 251 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); 252 | 253 | if (NULL != hProcess) { 254 | HMODULE hMod; 255 | DWORD cbNeeded; 256 | 257 | if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) { 258 | wchar_t szProcessName[MAX_PATH]; 259 | if (GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName) / sizeof(wchar_t))) { 260 | processName = szProcessName; 261 | } 262 | } 263 | else 264 | { 265 | std::wcout << L"[-] EnumProcessModules() Failed: " << GetLastError() << std::endl; 266 | } 267 | 268 | CloseHandle(hProcess); 269 | } 270 | 271 | return processName; 272 | } 273 | 274 | void ShowBanner() 275 | { 276 | std::cout << R"( 277 | 278 | ,_ _ _, 279 | \o-o/ 280 | ,(.-.), 281 | _/ |) (| \_ 282 | /\=-=/\ 283 | ,| \=/ |, 284 | _/ \ | / \_ 285 | \_!_/ 286 | 287 | MonikerHound - find your own UAC Bypass! 288 | )" << std::endl; 289 | 290 | std::wcout << L"\t CICADA8 Research Team" << std::endl; 291 | std::wcout << L"\t From Michael Zhmaylo (MzHmO)\n" << std::endl; 292 | } 293 | 294 | int main() 295 | { 296 | ShowBanner(); 297 | std::vector clsids = EnumerateCLSID(); 298 | 299 | if (clsids.empty()) 300 | { 301 | std::wcerr << L"Cant get CLSIDs" << std::endl; 302 | return -1; 303 | } 304 | 305 | CoInitialize(NULL); 306 | 307 | HRESULT hr; 308 | 309 | for (const auto& wsclsid : clsids) 310 | { 311 | std::wstring registryPath = L"SOFTWARE\\Classes\\CLSID\\" + wsclsid; 312 | 313 | std::wstring name; 314 | bool nameValueExists = GetDefaultRegistryValue(HKEY_LOCAL_MACHINE, registryPath, name); 315 | 316 | std::wstring localizedString; 317 | bool localizedStringExists = CheckRegistryValue(HKEY_LOCAL_MACHINE, registryPath, L"LocalizedString", localizedString); 318 | 319 | std::wstring elevationPath = registryPath + L"\\Elevation"; 320 | bool elevationFolderExists = DoesKeyExist(HKEY_LOCAL_MACHINE, elevationPath); 321 | 322 | DWORD enabledValue; 323 | bool enabledExists = CheckRegistryDWORD(HKEY_LOCAL_MACHINE, elevationPath, L"Enabled", enabledValue); 324 | 325 | std::wstring iconReferenceValue; 326 | bool iconReferenceExists = CheckRegistryValue(HKEY_LOCAL_MACHINE, elevationPath, L"IconReference", iconReferenceValue); 327 | 328 | if (localizedStringExists && elevationFolderExists && enabledExists && iconReferenceExists) 329 | { 330 | std::wcout << L"[+] Potential COM server for elevation moniker found!" << std::endl; 331 | std::wcout << L"Name: " << name << std::endl; 332 | std::wcout << L"CLSID: " << wsclsid << std::endl; 333 | std::wcout << L"LocalizedString: " << localizedString << std::endl; 334 | std::wcout << L"Enabled: " << enabledValue << std::endl; 335 | std::wcout << L"IconReference: " << iconReferenceValue << std::endl; 336 | 337 | CComPtr pUnknown; 338 | CLSID clsid; 339 | 340 | hr = CLSIDFromString(wsclsid.c_str(), &clsid); 341 | if (FAILED(hr)) 342 | { 343 | std::wcout << L"Activate: Failed (CLSIDFromString Err:" << hr << L")" << std::endl; 344 | continue; 345 | } 346 | 347 | hr = CoCreateInstanceAsAdmin(NULL, clsid, IID_IUnknown, (void**)&pUnknown); 348 | 349 | if (FAILED(hr)) 350 | { 351 | std::wcout << L"Activate: Failed (CoCreateInstanceAsAdmin Err:" << hr << L")" << std::endl; 352 | continue; 353 | } 354 | 355 | std::wcout << L"Activate: Success" << std::endl; 356 | 357 | DWORD pid; 358 | if (GetPIDFromIUnknown(pUnknown, &pid)) 359 | { 360 | std::wcout << L"PID: " << pid << std::endl; 361 | std::wcout << GetProcessName(pid) << std::endl; 362 | } 363 | 364 | std::wcout << L"[+]........................[+]" << std::endl; 365 | } 366 | } 367 | 368 | 369 | 370 | return 0; 371 | } -------------------------------------------------------------------------------- /MonikerHound/x64/Debug/MonikerHound.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/MonikerHound/x64/Debug/MonikerHound.exe -------------------------------------------------------------------------------- /MonikerHound/x64/Debug/MonikerHound.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/MonikerHound/x64/Debug/MonikerHound.pdb -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34009.444 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PermissionHunter", "PermissionHunter\PermissionHunter.csproj", "{8451644F-7BD5-4137-9252-CD5538069563}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {8451644F-7BD5-4137-9252-CD5538069563}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {8451644F-7BD5-4137-9252-CD5538069563}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {8451644F-7BD5-4137-9252-CD5538069563}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {8451644F-7BD5-4137-9252-CD5538069563}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {2A3FD99A-D27D-4D02-867A-6B2BCA818FA9} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/PermissionHunter.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {8451644F-7BD5-4137-9252-CD5538069563} 8 | Exe 9 | PermissionHunter 10 | PermissionHunter 11 | v4.8 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\Microsoft.Office.Interop.Excel.15.0.4795.1001\lib\net20\Microsoft.Office.Interop.Excel.dll 38 | True 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Security.AccessControl; 7 | using System.Security.Principal; 8 | using System.Collections.Concurrent; 9 | using System.Threading.Tasks; 10 | using Excel = Microsoft.Office.Interop.Excel; 11 | using System.Reflection; 12 | 13 | namespace PermissionHunter 14 | { 15 | public class SDInfo 16 | { 17 | public string Principal { get; set; } 18 | public string Type { get; set; } 19 | public int AccessMask { get; set; } 20 | public List Access { get; set; } 21 | public SecurityIdentifier SID { get; set; } 22 | } 23 | 24 | public class ObjectInfo 25 | { 26 | public string ApplicationID { get; set; } 27 | public string ApplicationName { get; set; } 28 | public string RunAs { get; set; } 29 | public string AuthLevel { get; set; } 30 | public string ImpLevel { get; set; } 31 | public List CLSIDs { get; set; } 32 | 33 | public List AccessInfo { get; set; } 34 | public List LaunchInfo { get; set; } 35 | } 36 | 37 | public class Parser 38 | { 39 | const int COM_RIGHTS_EXECUTE = 1; 40 | const int COM_RIGHTS_EXECUTE_LOCAL = 2; 41 | const int COM_RIGHTS_EXECUTE_REMOTE = 4; 42 | const int COM_RIGHTS_ACTIVATE_LOCAL = 8; 43 | const int COM_RIGHTS_ACTIVATE_REMOTE = 16; 44 | 45 | public static List GetDCOMObjects() 46 | { 47 | var result = new List(); 48 | 49 | foreach (var appID in GetAppIDs()) 50 | { 51 | var keyPath = $@"HKEY_CLASSES_ROOT\AppID\{appID}"; 52 | var obj = new ObjectInfo(); 53 | 54 | obj.ApplicationID = appID; 55 | obj.ApplicationName = GetValueFromRegistry(keyPath, ""); 56 | obj.RunAs = GetValueFromRegistry(keyPath, "RunAs"); 57 | 58 | if (string.IsNullOrEmpty(obj.RunAs)) 59 | { 60 | obj.RunAs = "The Launching User"; 61 | } 62 | 63 | obj.AccessInfo = GetPermissionsForAppID(keyPath, "AccessPermission"); 64 | obj.LaunchInfo = GetPermissionsForAppID(keyPath, "LaunchPermission"); 65 | obj.CLSIDs = GetCLSIDsFromAppid(obj.ApplicationID); 66 | 67 | result.Add(obj); 68 | } 69 | 70 | return result; 71 | } 72 | 73 | private static List GetCLSIDsFromAppid(string appID) 74 | { 75 | var list = new List(); 76 | 77 | using (RegistryKey clsidRoot = Registry.ClassesRoot.OpenSubKey("CLSID")) 78 | { 79 | if (clsidRoot == null) 80 | { 81 | Console.WriteLine("[-] Cant open HKCR\\CLSID."); 82 | return list; 83 | } 84 | 85 | var clsidNames = clsidRoot.GetSubKeyNames(); 86 | var partitioner = Partitioner.Create(clsidNames, EnumerablePartitionerOptions.NoBuffering); 87 | 88 | var concurrentBag = new ConcurrentBag(); 89 | 90 | Parallel.ForEach(partitioner, clsid => 91 | { 92 | using (var subKey = clsidRoot.OpenSubKey(clsid)) 93 | { 94 | if (subKey == null) return; 95 | 96 | object appidValue = subKey.GetValue("AppID"); 97 | 98 | if (appidValue is string appid && appid == appID) 99 | { 100 | concurrentBag.Add(clsid); 101 | } 102 | } 103 | }); 104 | 105 | list = concurrentBag.ToList(); 106 | } 107 | 108 | return list; 109 | } 110 | 111 | private static List GetPermissionsForAppID(string keyPath, string permissionName) 112 | { 113 | var result = new List(); 114 | 115 | try 116 | { 117 | var regPerms = (byte[])Registry.GetValue(keyPath, permissionName, null); 118 | if (regPerms == null) 119 | { 120 | // Console.WriteLine($"[-] Cant get {permissionName} for {keyPath}"); 121 | } 122 | 123 | var sd = new RawSecurityDescriptor(regPerms, 0); 124 | 125 | foreach (CommonAce ace in sd.DiscretionaryAcl) 126 | { 127 | var access = new List(); 128 | var userName = ""; 129 | var sid = ace.SecurityIdentifier; 130 | 131 | try 132 | { 133 | userName = sid.Translate(typeof(NTAccount)).ToString(); 134 | } 135 | catch 136 | { 137 | //Console.WriteLine("Unable to map SID to username"); 138 | } 139 | 140 | if (permissionName == "LaunchPermission") 141 | { 142 | if ((ace.AccessMask & COM_RIGHTS_EXECUTE_LOCAL) != 0 || 143 | ((ace.AccessMask & COM_RIGHTS_EXECUTE) != 0 && 144 | (ace.AccessMask & (COM_RIGHTS_EXECUTE_REMOTE | COM_RIGHTS_ACTIVATE_REMOTE | COM_RIGHTS_ACTIVATE_LOCAL)) == 0)) 145 | { 146 | access.Add("LocalLaunch"); 147 | } 148 | 149 | if ((ace.AccessMask & COM_RIGHTS_EXECUTE_REMOTE) != 0 || 150 | ((ace.AccessMask & COM_RIGHTS_EXECUTE) != 0 && 151 | (ace.AccessMask & (COM_RIGHTS_EXECUTE_LOCAL | COM_RIGHTS_ACTIVATE_REMOTE | COM_RIGHTS_ACTIVATE_LOCAL)) == 0)) 152 | { 153 | access.Add("RemoteLaunch"); 154 | } 155 | 156 | if ((ace.AccessMask & COM_RIGHTS_ACTIVATE_LOCAL) != 0 || 157 | ((ace.AccessMask & COM_RIGHTS_EXECUTE) != 0 && 158 | (ace.AccessMask & (COM_RIGHTS_EXECUTE_LOCAL | COM_RIGHTS_EXECUTE_REMOTE | COM_RIGHTS_ACTIVATE_REMOTE)) == 0)) 159 | { 160 | access.Add("LocalActivation"); 161 | } 162 | 163 | if ((ace.AccessMask & COM_RIGHTS_ACTIVATE_REMOTE) != 0 || 164 | ((ace.AccessMask & COM_RIGHTS_EXECUTE) != 0 && 165 | (ace.AccessMask & (COM_RIGHTS_EXECUTE_LOCAL | COM_RIGHTS_EXECUTE_REMOTE | COM_RIGHTS_ACTIVATE_LOCAL)) == 0)) 166 | { 167 | access.Add("RemoteActivation"); 168 | } 169 | } 170 | else if (permissionName == "AccessPermission") 171 | { 172 | if ((ace.AccessMask & COM_RIGHTS_EXECUTE_LOCAL) != 0 || 173 | ((ace.AccessMask & COM_RIGHTS_EXECUTE) != 0 && 174 | (ace.AccessMask & COM_RIGHTS_EXECUTE_REMOTE) == 0)) 175 | { 176 | access.Add("LocalAccess"); 177 | } 178 | 179 | if ((ace.AccessMask & COM_RIGHTS_EXECUTE_REMOTE) != 0 || 180 | ((ace.AccessMask & COM_RIGHTS_EXECUTE) != 0 && 181 | (ace.AccessMask & COM_RIGHTS_EXECUTE_LOCAL) == 0)) 182 | { 183 | access.Add("RemoteAccess"); 184 | } 185 | } 186 | 187 | result.Add(new SDInfo 188 | { 189 | Access = access, 190 | AccessMask = ace.AccessMask, 191 | Type = ace.AceType.ToString(), 192 | SID = sid, 193 | Principal = userName 194 | }); 195 | } 196 | 197 | } 198 | catch (Exception ex) 199 | { 200 | 201 | } 202 | 203 | return result; 204 | } 205 | 206 | private static List GetAppIDs() 207 | { 208 | var list = new List(); 209 | var registryKey = $"AppID"; 210 | 211 | using (var key = Registry.ClassesRoot.OpenSubKey(registryKey)) 212 | { 213 | if (key != null) 214 | { 215 | foreach (var subkeyName in key.GetSubKeyNames()) 216 | { 217 | using (var subkey = key.OpenSubKey(subkeyName)) 218 | { 219 | if (subkey != null) 220 | { 221 | if (IsGuid(subkeyName)) 222 | { 223 | list.Add(subkeyName); 224 | } 225 | else 226 | { 227 | list.Add(subkey.GetValue("AppID") as string); 228 | } 229 | } 230 | } 231 | } 232 | } 233 | } 234 | return list; 235 | } 236 | 237 | private static bool IsGuid(string candidate) 238 | { 239 | return Guid.TryParse(candidate, out _); 240 | } 241 | 242 | private static string GetValueFromRegistry(string keyPath, string value) 243 | { 244 | return (string)Registry.GetValue(keyPath, value, null); 245 | } 246 | } 247 | 248 | 249 | internal class Program 250 | { 251 | static void Main(string[] args) 252 | { 253 | ShowBanner(); 254 | 255 | if (args.Length == 0) 256 | { 257 | Console.WriteLine("[?] You didn't specify anything. Look PermissionHunter.exe -h"); 258 | } 259 | 260 | var outFormat = "csv"; //csv / xlsx 261 | var outFile = $"Output"; 262 | foreach (var entry in args.Select((value, index) => new { index, value })) 263 | { 264 | var argument = entry.value.ToLower(); 265 | switch (argument) 266 | { 267 | case "-outformat": 268 | outFormat = args[entry.index + 1]; 269 | break; 270 | 271 | case "-outfile": 272 | outFile = args[entry.index + 1]; 273 | break; 274 | 275 | case "-h": 276 | case "--help": 277 | ShowHelp(); 278 | Environment.Exit(0); 279 | break; 280 | } 281 | } 282 | 283 | Console.WriteLine($"[+] Result will be in {outFile}, format {outFormat}"); 284 | 285 | var objects = Parser.GetDCOMObjects(); 286 | 287 | switch (outFormat) 288 | { 289 | case "csv": 290 | try 291 | { 292 | var csvFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{outFile}.{outFormat}"); 293 | 294 | using (var writer = new StreamWriter(csvFilePath, false, System.Text.Encoding.UTF8)) 295 | { 296 | var headers = new string[] { "ApplicationID", "ApplicationName", "RunAs", 297 | "LaunchAccess", "LaunchType", "LaunchPrincipal", "LaunchSID", 298 | "AccessAccess", "AccessType", "AccessPrincipal", "AccessSID", 299 | "AuthLevel", "ImpLevel", "CLSIDs"}; 300 | writer.WriteLine(string.Join(",", headers)); 301 | 302 | foreach (var obj in objects) 303 | { 304 | var clsids = ""; 305 | if (obj.CLSIDs != null) 306 | { 307 | clsids = string.Join(";", obj.CLSIDs); 308 | } 309 | var maxEntries = Math.Max(obj.LaunchInfo.Count, obj.AccessInfo.Count); 310 | 311 | for (var i = 0; i < maxEntries; i++) 312 | { 313 | var launch = (i < obj.LaunchInfo.Count) ? obj.LaunchInfo[i] : null; 314 | var access = (i < obj.AccessInfo.Count) ? obj.AccessInfo[i] : null; 315 | 316 | var row = new string[] 317 | { 318 | obj.ApplicationID, 319 | obj.ApplicationName, 320 | obj.RunAs, 321 | launch != null ? string.Join(". ", launch.Access) : "", 322 | launch != null ? launch.Type : "", 323 | launch != null ? launch.Principal : "", 324 | launch != null ? launch.SID.ToString() : "", 325 | access != null ? string.Join(". ", access.Access) : "", 326 | access != null ? access.Type : "", 327 | access != null ? access.Principal : "", 328 | access != null ? access.SID.ToString() : "", 329 | obj.AuthLevel, 330 | obj.ImpLevel, 331 | clsids 332 | }; 333 | 334 | writer.WriteLine(string.Join(", ", row)); 335 | } 336 | } 337 | } 338 | } 339 | catch (Exception ex) 340 | { 341 | Console.WriteLine("[-] Could not write to CSV file."); 342 | Console.WriteLine(ex.Message); 343 | } 344 | 345 | 346 | break; 347 | 348 | case "xlsx": 349 | try 350 | { 351 | 352 | var excelFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{outFile}.{outFormat}"); 353 | 354 | var excelApp = new Excel.Application(); 355 | excelApp.Visible = false; 356 | excelApp.DisplayAlerts = false; 357 | 358 | var workBook = excelApp.Workbooks.Add(Missing.Value); 359 | var workSheet = (Excel.Worksheet)workBook.Worksheets[1]; 360 | 361 | var headers = new string[] { "ApplicationID", "ApplicationName", "RunAs", 362 | "LaunchAccess", "LaunchType", "LaunchPrincipal", "LaunchSID", 363 | "AccessAccess", "AccessType", "AccessPrincipal", "AccessSID", 364 | "AuthLevel", "ImpLevel", "CLSIDs"}; 365 | for (var i = 0; i < headers.Length; i++) 366 | { 367 | workSheet.Cells[1, i + 1] = headers[i]; 368 | var headerCell = (Excel.Range)workSheet.Cells[1, i + 1]; 369 | headerCell.Font.Bold = true; 370 | headerCell.BorderAround2(Excel.XlLineStyle.xlContinuous); 371 | } 372 | 373 | var rowIndex = 2; 374 | 375 | foreach (var obj in objects) 376 | { 377 | var clsids = ""; 378 | if (obj.CLSIDs != null) 379 | { 380 | clsids = string.Join(";", obj.CLSIDs); 381 | } 382 | var maxEntries = Math.Max(obj.LaunchInfo.Count, obj.AccessInfo.Count); 383 | 384 | for (var i = 0; i < maxEntries; i++) 385 | { 386 | var launch = (i < obj.LaunchInfo.Count) ? obj.LaunchInfo[i] : null; 387 | var access = (i < obj.AccessInfo.Count) ? obj.AccessInfo[i] : null; 388 | 389 | var row = new object[] 390 | { 391 | obj.ApplicationID, 392 | obj.ApplicationName, 393 | obj.RunAs, 394 | launch != null ? string.Join(". ", launch.Access) : "", 395 | launch != null ? launch.Type : "", 396 | launch != null ? launch.Principal : "", 397 | launch != null ? launch.SID.ToString() : "", 398 | access != null ? string.Join(". ", access.Access) : "", 399 | access != null ? access.Type : "", 400 | access != null ? access.Principal : "", 401 | access != null ? access.SID.ToString() : "", 402 | obj.AuthLevel, 403 | obj.ImpLevel, 404 | clsids 405 | }; 406 | 407 | for (var j = 0; j < row.Length; j++) 408 | { 409 | workSheet.Cells[rowIndex, j + 1] = row[j]; 410 | var cell = (Excel.Range)workSheet.Cells[rowIndex, j + 1]; 411 | //cell.BorderAround2(Excel.XlLineStyle.xlContinuous); 412 | } 413 | rowIndex++; 414 | } 415 | } 416 | 417 | workBook.SaveAs(excelFilePath); 418 | workBook.Close(false, Missing.Value, Missing.Value); 419 | excelApp.Quit(); 420 | } 421 | catch (Exception ex) 422 | { 423 | Console.WriteLine("[-] Do you have Excel? :D"); 424 | Console.WriteLine(ex.Message); 425 | } 426 | 427 | break; 428 | 429 | default: 430 | Console.WriteLine($"[-] Invalid format {outFormat}"); 431 | break; 432 | } 433 | 434 | Console.WriteLine("[+] Success"); 435 | } 436 | 437 | 438 | private static void ShowBanner() 439 | { 440 | var art = @" 441 | , 442 | `-. \ .-' 443 | ,-""`````""""-\__ | / 444 | '-.._ _.-'` '-o, 445 | _>--:{{< ) |) 446 | .-'' '-.__.-o` 447 | '-._____..-/` | \ 448 | ,-' / `-. 449 | ` 450 | PermissionHunter - hunt for incorrect LaunchPermission and ActivatePermission 451 | "; 452 | 453 | Console.WriteLine(art); 454 | Console.WriteLine("\tCICADA8 Research Team"); 455 | Console.WriteLine("\tFrom Michael Zhmaylo (MzHmO)"); 456 | Console.WriteLine(""); 457 | } 458 | 459 | private static void ShowHelp() 460 | { 461 | Console.WriteLine("PermissionHunter.exe"); 462 | Console.WriteLine("Small tool that allows you to find vulnerable COM objects with incorrect LaunchPermission and ActivatePermission"); 463 | Console.WriteLine(); 464 | Console.WriteLine("[OPTIONS]"); 465 | Console.WriteLine("-outfile : output filename"); 466 | Console.WriteLine("-outformat : output format. Accepted 'csv' and 'xlsx'"); 467 | Console.WriteLine("-h/--help : shows this windows"); 468 | Console.WriteLine(); 469 | } 470 | } 471 | } 472 | -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Общие сведения об этой сборке предоставляются следующим набором 6 | // набора атрибутов. Измените значения этих атрибутов для изменения сведений, 7 | // связанные с этой сборкой. 8 | [assembly: AssemblyTitle("PermissionHunter")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("PermissionHunter")] 13 | [assembly: AssemblyCopyright("Copyright © 2024")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми 18 | // для компонентов COM. Если необходимо обратиться к типу в этой сборке через 19 | // из модели COM задайте для атрибута ComVisible этого типа значение true. 20 | [assembly: ComVisible(false)] 21 | 22 | // Следующий GUID представляет идентификатор typelib, если этот проект доступен из модели COM 23 | [assembly: Guid("8451644f-7bd5-4137-9252-cd5538069563")] 24 | 25 | // Сведения о версии сборки состоят из указанных ниже четырех значений: 26 | // 27 | // Основной номер версии 28 | // Дополнительный номер версии 29 | // Номер сборки 30 | // Номер редакции 31 | // 32 | // Можно задать все значения или принять номера сборки и редакции по умолчанию 33 | // используя "*", как показано ниже: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/bin/Debug/PermissionHunter.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/PermissionHunter/PermissionHunter/PermissionHunter/bin/Debug/PermissionHunter.exe -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/bin/Debug/PermissionHunter.exe.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/bin/Debug/PermissionHunter.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/PermissionHunter/PermissionHunter/PermissionHunter/bin/Debug/PermissionHunter.pdb -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/bin/Debug/result.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/PermissionHunter/PermissionHunter/PermissionHunter/bin/Debug/result.xlsx -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/obj/Debug/.NETFramework,Version=v4.8.AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using System.Reflection; 4 | [assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] 5 | -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/PermissionHunter/PermissionHunter/PermissionHunter/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/obj/Debug/PermissionHunter.csproj.AssemblyReference.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/PermissionHunter/PermissionHunter/PermissionHunter/obj/Debug/PermissionHunter.csproj.AssemblyReference.cache -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/obj/Debug/PermissionHunter.csproj.CoreCompileInputs.cache: -------------------------------------------------------------------------------- 1 | 02f28a3428f9fc008fbd0f89bc4c0004c7de5b83 2 | -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/obj/Debug/PermissionHunter.csproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | A:\SSD\gitrepo\COMThanasia\PermissionHunter\PermissionHunter\PermissionHunter\obj\Debug\PermissionHunter.csproj.AssemblyReference.cache 2 | A:\SSD\gitrepo\COMThanasia\PermissionHunter\PermissionHunter\PermissionHunter\obj\Debug\PermissionHunter.csproj.CoreCompileInputs.cache 3 | A:\SSD\gitrepo\COMThanasia\PermissionHunter\PermissionHunter\PermissionHunter\bin\Debug\PermissionHunter.exe.config 4 | A:\SSD\gitrepo\COMThanasia\PermissionHunter\PermissionHunter\PermissionHunter\bin\Debug\PermissionHunter.exe 5 | A:\SSD\gitrepo\COMThanasia\PermissionHunter\PermissionHunter\PermissionHunter\bin\Debug\PermissionHunter.pdb 6 | A:\SSD\gitrepo\COMThanasia\PermissionHunter\PermissionHunter\PermissionHunter\obj\Debug\PermissionHunter.exe 7 | A:\SSD\gitrepo\COMThanasia\PermissionHunter\PermissionHunter\PermissionHunter\obj\Debug\PermissionHunter.pdb 8 | -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/obj/Debug/PermissionHunter.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/PermissionHunter/PermissionHunter/PermissionHunter/obj/Debug/PermissionHunter.exe -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/obj/Debug/PermissionHunter.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/PermissionHunter/PermissionHunter/PermissionHunter/obj/Debug/PermissionHunter.pdb -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/PermissionHunter/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/packages/Microsoft.Office.Interop.Excel.15.0.4795.1001/.signature.p7s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/PermissionHunter/PermissionHunter/packages/Microsoft.Office.Interop.Excel.15.0.4795.1001/.signature.p7s -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/packages/Microsoft.Office.Interop.Excel.15.0.4795.1001/Microsoft.Office.Interop.Excel.15.0.4795.1001.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/PermissionHunter/PermissionHunter/packages/Microsoft.Office.Interop.Excel.15.0.4795.1001/Microsoft.Office.Interop.Excel.15.0.4795.1001.nupkg -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/packages/Microsoft.Office.Interop.Excel.15.0.4795.1001/lib/net20/Microsoft.Office.Interop.Excel.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/PermissionHunter/PermissionHunter/packages/Microsoft.Office.Interop.Excel.15.0.4795.1001/lib/net20/Microsoft.Office.Interop.Excel.dll -------------------------------------------------------------------------------- /PermissionHunter/PermissionHunter/packages/Microsoft.Office.Interop.Excel.15.0.4795.1001/lib/netstandard2.0/Microsoft.Office.Interop.Excel.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CICADA8-Research/COMThanasia/903e83ab569fef88b47d8a1d607bf44669d60da1/PermissionHunter/PermissionHunter/packages/Microsoft.Office.Interop.Excel.15.0.4795.1001/lib/netstandard2.0/Microsoft.Office.Interop.Excel.dll -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # COMThanasia 2 | 3 | ## TL;DR 4 | With this tool, you will be able to detect: 5 | - Incorrect access control to a COM object (LaunchPermission , AccessPermission) - LPE through abusable COM methods, DCOM Authentication relaying. That's `PermissionHunter`. 6 | - Incorrect registry rights to a COM object - LPE through COM Hijacking. That's `ComDiver`. 7 | - Find new Elevation Moniker - UAC Bypass. That's `MonikerHound`. 8 | - Get detailed information about a specific CLSID - Inspect COM object to find abusable COM Methods. That's `ClsidExplorer`. 9 | - Check Cross-Session Activation on behalf of a low-privileged user - Attempting to instantiate an object in someone else's session for LPE. That's `ComTraveller`. 10 | 11 | If we had published this tool a couple months ago (e.g. Spring 2024), you would have discovered CVE-2024-38100 (FakePotato) and CVE-2024-38061 (SilverPotato). 12 | 13 | Start using this tool and you can find more ways to elevate privilege on Windows systems. It's like an automated OleViewDotnet :) 14 | 15 | ![изображение](https://github.com/user-attachments/assets/57dc0eaa-4fbf-47e7-a65a-e7d0ef5960d5) 16 | 17 | 18 | ## PermissionHunter 19 | ### What is this 20 | PermissionHunter is a tool that allows you to examine LaunchPermission and ActivatePermission on all COM objects on the system. 21 | 22 | ```shell 23 | PS A:\mzhmo> .\PermissionHunter.exe -h 24 | 25 | , 26 | `-. \ .-' 27 | ,-"`````""-\__ | / 28 | '-.._ _.-'` '-o, 29 | _>--:{{< ) |) 30 | .-'' '-.__.-o` 31 | '-._____..-/` | \ 32 | ,-' / `-. 33 | ` 34 | PermissionHunter - hunt for incorrect LaunchPermission and ActivatePermission 35 | 36 | CICADA8 Research Team 37 | From Michael Zhmaylo (MzHmO) 38 | 39 | PermissionHunter.exe 40 | Small tool that allows you to find vulnerable COM objects with incorrect LaunchPermission and ActivatePermission 41 | 42 | [OPTIONS] 43 | -outfile : output filename 44 | -outformat : output format. Accepted 'csv' and 'xlsx' 45 | -h/--help : shows this windows 46 | ``` 47 | There are only two arguments here: 48 | - `-outfile` - name of the file with the rights report; 49 | - `-outformat` - format of the file with the report, you can output both in csv and xlsx. It is better to output in csv, because if you do not have Excel, you will not be able to output in xlsx format. 50 | 51 | ### Usage 52 | Example: 53 | ```shell 54 | PS A:\mzhmo> .\PermissionHunter -outfile result -outformat xlsx 55 | 56 | , 57 | `-. \ .-' 58 | ,-"`````""-\__ | / 59 | '-.._ _.-'` '-o, 60 | _>--:{{< ) |) 61 | .-'' '-.__.-o` 62 | '-._____..-/` | \ 63 | ,-' / `-. 64 | ` 65 | PermissionHunter - hunt for incorrect LaunchPermission and ActivatePermission 66 | 67 | CICADA8 Research Team 68 | From Michael Zhmaylo (MzHmO) 69 | 70 | [+] Result will be in result, format xlsx 71 | [+] Success 72 | ``` 73 | 74 | After that you will get a file result.xlsx, which will list all rights to existing COM objects. 75 | ![изображение](https://github.com/user-attachments/assets/f72ec28c-02b5-40e0-a262-af842d58f94d) 76 | 77 | I output the following columns: 78 | - `ApplicationID` - ApplicationID of a specific COM object. Ex: `{69AD4AEE-51BE-439b-A92C-86AE490E8B30}`; 79 | - `ApplicationName` - ApplicationName of a specific COM object. Ex: `Background Intelligent Transfer Service`; 80 | - `RunAs` - RunAs registry key of a COM object. Ex: `Interactive User`; 81 | - `LaunchAccess`, `LaunchType`, `LaunchPrincipal`, `LaunchSid` - LaunchPermission registry key. LaunchPrincipal specifies the user who has LaunchAccess rights to the COM object. LaunchType - type of ACE: enabling or disabling. LaunchSID - SID of LaunchPrincipal. Ex: 82 | ```shell 83 | LocalLaunch. RemoteLaunch. LocalActivation. RemoteActivation AccessAllowed NT AUTHORITY\SYSTEM S-1-5-18 84 | ``` 85 | This means that the system has LocalLaunch, RemoteLaunch, LocalActivation, RemoteActivation permissions on this COM object; 86 | - `AccessAccess`, `AccessType`, `AccessPrincipal`, `AccessSID` - fields have the same meaning as LaunchPermissions, only in the context of AccessPermission; 87 | - `AuthLevel`, `ImpLevel` - Authentication Level and Impersonation Level. By default they are set to `RPC_C_AUTHN_LEVEL_CONNECT` and `RPC_C_IMP_LEVEL_IDENTIFY`; 88 | - `CLSIDs` - COM object CLSIDs. 89 | 90 | ### How to abuse 91 | If you find a COM object that you can access on behalf of a low-privileged user, for example, you can abuse it as follows: 92 | 1. Create an instance and call the methods of that COM object to, for example, write an arbitrary file on behalf of the system. For example, you have found a COM object with a `DeployCmdShell()` method that runs on behalf of the `NT AUTHORITY\SYSTEM` account and you have `LaunchPermissions` and `AccessPermissions`. You can start this COM object, call the `DeployCmdShell()` method, and get code execution on behalf of the system. You can view the available methods using `ClsidExplorer`. 93 | 2. Abuse DCOM authentication. For this, see [RemoteKrbRelay](https://github.com/CICADA8-Research/RemoteKrbRelay/tree/main) 94 | 95 | ## ComDiver 96 | ### What is this 97 | All information about COM objects is in the registry. But what if the registration was incorrect? In such a case we have a possibility to override COM settings, for example, to hijack the executable file. 98 | 99 | This tool allows you to detect such vulnerabilities, and it scans the registry according to the priority of keys that are viewed when searching for COM objects. In this way, you can even find Shadow COM Hijacking. The priority is as follows: 100 | ```shell 101 | 1. HKCU\Software\Classes\(GUID)\TreatAs 102 | 103 | 2. HKLM\Software\Classes\(GUID)\TreatAs 104 | 105 | 3. HKCU\Software\Classes\(GUID)\InprocServer32 106 | 107 | 4. HKLM\Software\Classes\(GUID)\InprocServer32 108 | 109 | 5. HKCU\Software\Classes\(GUID)\LocalServer32 110 | 111 | 6. HKLM\Software\Classes\(GUID)\LocalServer32 112 | ``` 113 | 114 | Thus at least two vectors of privilege escalation emerge: 115 | 1. If we have write permissions to `HKCU...TreatAs`, and the original COM executable is in `HKCU...LocalServer32`, then we can do Shadow COM Hijacking by writing our executable to `HKCU..TreatAs`. 116 | 2. If the COM object lies in `HKCU..LocalServer32` and we can write to `HKCU..LocalServer32`, then we can do COM Hijacking 117 | 118 | Let's take a closer look at the tool: 119 | ```shell 120 | PS A:\ssd\gitrepo\COMThanasia\ComDiver\x64\Debug> .\ComDiver.exe -h 121 | 122 | \ / 123 | \ o ^ o / 124 | \ ( ) / 125 | ____________(%%%%%%%)____________ 126 | ( / / )%%%%%%%( \ \ ) 127 | (___/___/__/ \__\___\___) 128 | ( / /(%%%%%%%)\ \ ) 129 | (__/___/ (%%%%%%%) \___\__) 130 | /( )\ 131 | / (%%%%%) \ 132 | (%%%) 133 | ! 134 | 135 | ----------- COM DIVER -------------- 136 | [?] Small tool to check insecure registry and disk permissions on com objects 137 | [?] ARGS 138 | -h/--help <- show this message 139 | --from <- analyze CLSIDs from this clsid 140 | --target <- analyze one target clsid 141 | --no-context <- dont check another COM-server context. Only registry analyzing. 142 | --no-create <- dont create target COM object. This is the fastest mode 143 | ``` 144 | It accepts the following arguments: 145 | - `--from` - there are a lot of CLSIDs on a Windows system. If you do not want the tool to look at all CLSIDs starting from the first, you can specify the CLSID to start with, for example, `--from {50FDBB99-5C92-495E-9E81-E2C2F48CDDA}` 146 | - `--target` - analyze specific clsid; 147 | - `--no-context` - do not check the name of the user on whose behalf the COM object is launched; 148 | - `--no-create` - not to create a COM object that has been detected. This limits the information you can get about it. However, this is the fastest way to examine only the registry rights. 149 | 150 | ### Usage 151 | Example: 152 | ```shell 153 | .\ComDiver.exe --no-create 154 | ``` 155 | ![изображение](https://github.com/user-attachments/assets/737534c3-27b2-41cf-9987-a94019aadb2a) 156 | 157 | In this case we can see that there are no keys inside HKCU and we have write permissions to those keys. Accordingly, if we write our own value to this path, we will do COM Hijacking. 158 | 159 | ### How to abuse 160 | If you see red in lines in the tool output, this is a potential way to abuse a COM object! You can perform COM Hijacking (spoofing an existing executable), or Shadow COM Hijacking (spoofing a missing executable). Read more about COM Hijacking [here](https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation/com-hijacking) 161 | 162 | ## MonikerHound 163 | ### What is this 164 | There is a built-in way to bypass UAC on a Windows system, this is done through Elevation Moniker. You can read more about it [here](https://learn.microsoft.com/en-us/windows/win32/com/the-com-elevation-moniker). This kind of UAC Bypass requires a non-standard way of registering the COM object in the registry, which is fairly easy to trace. So you can use my tool to find new ways of UAC Bypass. 165 | 166 | There are some examples: 167 | - https://github.com/0xlane/BypassUAC 168 | - https://github.com/Wh04m1001/IDiagnosticProfileUAC 169 | 170 | ### Usage 171 | Example: 172 | ```shell 173 | PS A:\ssd\gitrepo\COMThanasia\MonikerHound\x64\Debug> .\MonikerHound.exe 174 | 175 | 176 | ,_ _ _, 177 | \o-o/ 178 | ,(.-.), 179 | _/ |) (| \_ 180 | /\=-=/\ 181 | ,| \=/ |, 182 | _/ \ | / \_ 183 | \_!_/ 184 | 185 | MonikerHound - find your own UAC Bypass! 186 | 187 | CICADA8 Research Team 188 | From Michael Zhmaylo (MzHmO) 189 | 190 | [+] Potential COM server for elevation moniker found! 191 | Name: CEIPLuaElevationHelper 192 | CLSID: {01D0A625-782D-4777-8D4E-547E6457FAD5} 193 | LocalizedString: @%systemroot%\system32\werconcpl.dll,-351 194 | Enabled: 1 195 | IconReference: @%systemroot%\system32\werconcpl.dll,-6 196 | Activate: Success 197 | PID: 15800 198 | DllHost.exe 199 | [+]........................[+] 200 | [+] Potential COM server for elevation moniker found! 201 | Name: CTapiLuaLib Class 202 | CLSID: {03e15b2e-cca6-451c-8fb0-1e2ee37a27dd} 203 | LocalizedString: @%systemroot%\system32\tapiui.dll,-1 204 | Enabled: 1 205 | IconReference: @%systemroot%\system32\tapiui.dll,-201 206 | Activate: Success 207 | PID: 440 208 | DllHost.exe 209 | [+]........................[+] 210 | ``` 211 | 212 | ### How to abuse 213 | Once you have discovered potential candidates for UAC Bypass, you can start checking them out. As a great template for running Elevation Moniker, you can take [this function](https://github.com/CICADA8-Research/COMThanasia/blob/main/MonikerHound/MonikerHound/Source.cpp#L183), or this [program](https://github.com/0xlane/BypassUAC). 214 | 215 | 216 | ## ClsidExplorer 217 | ### What is this 218 | ClsidExplorer allows you to retrieve information about a specific CLSID. The program outputs the following data: 219 | - `AppID` - ApplicationID of a specific COM Object; 220 | - `ProgID` - ProgID of a specific COM Object; 221 | - `PID` - PID in which this COM Object is running; 222 | - `Process Name` - the name of the PID process; 223 | - `Username` - name of the user on whose behalf the process is running; 224 | - `Methods` - available methods of the COM Object. Made by parsing TypeLib. 225 | 226 | ```shell 227 | PS A:\ssd\gitrepo\COMThanasia\ClsidExplorer\x64\Debug> .\CLSIDExplorer.exe -h 228 | CLSIDExplorer.exe - identify all info by clsid 229 | Usage: 230 | .\CLSIDExplorer.exe --clsid "{00000618-0000-0010-8000-00aa006d2ea4}" 231 | ``` 232 | The program accepts only one argument: 233 | - `--clsid` - target CLSID to analyze 234 | 235 | ### Example 236 | ```shell 237 | PS A:\ssd\gitrepo\COMThanasia\ClsidExplorer\x64\Debug> .\CLSIDExplorer.exe --clsid "{00000618-0000-0010-8000-00aa006d2ea4}" 238 | [{00000618-0000-0010-8000-00aa006d2ea4}] 239 | AppID: Unknown 240 | ProgID: Unknown 241 | PID: 1572 242 | Process Name: CLSIDExplorer.exe 243 | Username: WINPC\\Michael 244 | Methods: 245 | [0] __stdcall void QueryInterface(IN GUID*, OUT void**) 246 | [1] __stdcall unsigned long AddRef() 247 | [2] __stdcall unsigned long Release() 248 | [3] __stdcall void GetTypeInfoCount(OUT unsigned int*) 249 | [4] __stdcall void GetTypeInfo(IN unsigned int, IN unsigned long, OUT void**) 250 | [5] __stdcall void GetIDsOfNames(IN GUID*, IN char**, IN unsigned int, IN unsigned long, OUT long*) 251 | [6] __stdcall void Invoke(IN long, IN GUID*, IN unsigned long, IN unsigned short, IN DISPPARAMS*, OUT VARIANT*, OUT EXCEPINFO*, OUT unsigned int*) 252 | [7] __stdcall BSTR Name() 253 | [8] __stdcall void Name(IN BSTR) 254 | [9] __stdcall RightsEnum GetPermissions(IN VARIANT, IN ObjectTypeEnum, IN VARIANT) 255 | [10] __stdcall void SetPermissions(IN VARIANT, IN ObjectTypeEnum, IN ActionEnum, IN RightsEnum, IN InheritTypeEnum, IN VARIANT) 256 | [11] __stdcall void ChangePassword(IN BSTR, IN BSTR) 257 | [12] __stdcall Groups* Groups() 258 | [13] __stdcall Properties* Properties() 259 | [14] __stdcall _Catalog* ParentCatalog() 260 | [15] __stdcall void ParentCatalog(IN _Catalog*) 261 | [16] __stdcall void ParentCatalog(IN _Catalog*) 262 | [END] 263 | ``` 264 | 265 | ### How to abuse 266 | This program is great for checking a COM class discovered with `ComTraveller` or `PermissionHunter` or `MonikerHound` for interesting methods that can be abused. 267 | 268 | ## ComTraveller 269 | ### What is this 270 | ComTraveller - this tool allows you to explore all available COM objects. First, it allows you to quickly identify COM objects with interesting values (RunAs Interactive User), availability of TypeLib, and Cross-Session Activation capabilities. Thus, you can quickly detect objects that may be instantiated in another user session, leading to privilege escalation. 271 | 272 | ```shell 273 | PS A:\SSD\gitrepo\COMThanasia\ComTraveller\x64\Debug> .\ComTraveller.exe -h 274 | 275 | ,,_ 276 | zd$$??= 277 | z$$P? F:`c, _ 278 | d$$, `c'cc$$i ,cd$?R 279 | $$$$ cud$,?$$$i ,=P"2?z " 280 | $" " ?$$$,?$$$. ,-''`>, bzP 281 | 'cLdb,?$$,?$$$ ,h' "I$'J$P 282 | ... `?$$$,"$$,`$$h $$PxrF'd$" 283 | d$PP""?-,"?$$,?$h`$$,,$$'$F44" 284 | ?,,_`=4c,?=,"?hu?$`?L4$'? ' 285 | `""?==""=-"" `""-`'_,,,, 286 | .ccu?m?e?JC,-,"=? 287 | """=='?" 288 | 289 | ComTraveller - small tool to parse and extract information about all registered CLSIDs on the system 290 | Usage: 291 | --file - output filename. Default: output.csv 292 | --from - start exploring clsids from this clsid. (for ex. default enum from 1 to 9. with --from 4 will be from 4 to 9) 293 | --session - use if you want to check Cross-Session Activation in a specific session. Useful only with 'Run as interactive user COM objects' 294 | --target - analyze this CLSID 295 | -h/--help - shows this screen 296 | ``` 297 | - `--file` - name of the file to which information about COM objects will be output; 298 | - `--from` - there are a lot of CLSIDs on a Windows system. If you do not want the tool to look at all CLSIDs starting from the first, you can specify the CLSID to start with, for example, `--from {50FDBB99-5C92-495E-9E81-E2C2F48CDDA}` 299 | - `--session` - try to instantiate an object in someone else's session 300 | - `--target` - analyze only one target clsid 301 | 302 | ### Usage 303 | Example: 304 | ```shell 305 | .\ComTraveller.exe --file rep.csv --session 1 306 | ``` 307 | 308 | ![изображение](https://github.com/user-attachments/assets/1779405d-8314-44e4-bad6-abce7c421238) 309 | 310 | After that you will find a rep.csv file with information about COM objects. 311 | ![изображение](https://github.com/user-attachments/assets/e6753aff-3ea0-4e48-add0-6e88ed451fc3) 312 | There are several columns here: 313 | - `CLSID` - CLSID of the COM object; 314 | - `AppId` - APPID of the COM object; 315 | - `ProgId` - APPID of COM object; 316 | - `RunAs` - value in the RunAs registry. If value is `The Interactive User` or `NT AUTHORITY\SYSTEM`, you can try to make LPE; 317 | - `Username` - name of the user on whose behalf the COM object is run; 318 | - `PID` - the PID in which the COM object is running; 319 | - `ProcessName` - name of the process in which the COM-object is running; 320 | - `HasTypeLib` - whether the COM-object has TypeLib. If it does, you can give this object to `ClsidExplorer` to see the available methods; 321 | - `canCrossSessionActivate` - whether it is possible to abuse this COM class for LPE through activation in someone else's session. If value is `+` or the error is `ACCESS DENIED`, this could be a potential candidate for LPE. 322 | 323 | For example, if you apply filters, you will immediately find interesting COM classes :) Wow, is this a COM class that can be activated cross-sessionally and it works on behalf of the system? 324 | ![изображение](https://github.com/user-attachments/assets/820411a0-7bf9-4972-9a02-d30562329149) 325 | ![изображение](https://github.com/user-attachments/assets/517d3215-28b7-4e14-8010-9ff8e6253ec4) 326 | 327 | It should be noted that the program may crash due to the abundance of COM objects. In this case, you can restart it like this: 328 | ```shell 329 | .\ComTraveller.exe --file rep.csv --session 1 --from "{0006F071-0000-0000-C000-000000000046}" 330 | ``` 331 | ![изображение](https://github.com/user-attachments/assets/0db19ec0-98d6-40fe-9403-0bf846c82993) 332 | 333 | 334 | --------------------------------------------------------------------------------