报告编号:B6-2020-101001
报告来源:360-CERT
报告作者:houjingyi233
更新日期:2020-10-10
0x01 漏洞详情
说起dll劫持,可能很多人还以为这是一种非常鸡肋的漏洞。不过我有关注到一些安全研究者披露过一些比较特殊的dll劫持的场景能够导致LPE甚至RCE。前一段时间我无意中发现了cisco webex teams中的dll加载机制存在漏洞可以通过dll劫持实现本地提权,并且据我所知没有人提到过这种dll劫持的场景。
安装好cisco webex teams之后我发现它被安装到C:\Users\username\AppData\Local\CiscoSpark,我决定看一眼日志current_log.txt。
看起来有几个dll第一次没有加载成功,第二次才加载成功的。这很奇怪,CiscoCollabHost.exe想从dependencies目录中加载这些dll,error code 126意味着"The specified module could not be found",但是dependencies目录和CiscoCollabHost.exe是在同一个目录下的,并且dependencies目录里面也有这些dll。所以一定是哪里出了问题......
直到我在IDA中找到spark-windows-media.dll中对应的代码,又花了一些时间,我才意识这是怎么回事。
在AddDllDirectory的文档中微软说参数应该是"An absolute path to the directory to add to the search path"。不过微软并没有说不能用相对路径,也没有说如果你用了相对路径会发生什么。更坑爹的是如果你像这里一样用了L"\\dependencies"这样的相对路径,实际上windows会把它当成"C:\dependencies"!
我们可以自己写一段代码试一试:
PCWSTR pcwstr = L"\\dependencies";
if(!AddDllDirectory(pcwstr))
{
std::cout << "failed!\n";
}
LoadLibraryExW(L"test.dll", 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
std::cout << "Hello World!\n";
编译出poc.exe,然后把poc.exe放到C:\example\poc.exe,如果C:\dependencies\test.dll和C:\example\dependencies\test.dll同时存在,被加载的会是C:\dependencies\test.dll。
所以这里利用这个漏洞就很简单了,把wmeclient.dll放到C:\dependencies\wmeclient.dll,受害者打开cisco webex teams成功登录之后这个wmeclient.dll就会被cisco webex teams加载执行。直接将PE文件写到C盘根目录是需要管理员权限的,但是在C盘根目录创建一个目录然后把你的PE文件写到这个目录是不需要管理员权限的。
考虑另外一种exe和加载的dll不在同一个路径的情况,如果C:\abc\def\poc.exe想要加载C:\abc\lib\test.dll,可不可以写成LoadLibraryW(L"..\\lib\\test.dll")呢?这也是会导致漏洞的,同样windows会把"..\\lib\\test.dll"直接当成"C:\lib\test.dll"。我在另外某个知名厂商的产品中发现了这样的代码,我已经报告给了厂商,还在等厂商给我答复。我可能会在90天的期限或者厂商发布安全公告之后补充更多细节。
不仅仅是加载dll相关的路径windows是这么处理的,像CreateProcess这样的函数如果给它一个相对路径也可能导致漏洞。因为有些厂商的产品有windows版也有linux版,开发者可能会将这两个平台的代码混在一起,比如如果你写出了这样的代码:
TCHAR szCmdLine[] = {TEXT("\\bin\\whoami")};
STARTUPINFO si;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
PROCESS_INFORMATION pi;
CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
windows会加上C:\和.exe,也就是说把whoami.exe放到C:\bin\whoami.exe那么它就会被执行。我在cisco DCNM中发现了类似于这样的代码,它们告诉我这个问题只在server 2019上存在而server 2019并不是DCNM默认支持的环境,所以cisco将我报告的这个问题当成了bug处理:
https://bst.cloudapps.cisco.com/bugsearch/bug/CSCvv65124
我也向MSRC报告过我的发现,不过MSRC说这是default behavior。我觉得出现这些问题主要的锅还是微软。
漏洞产生和发现的过程都非常具有戏剧性:如果dll加载失败的时候开发者认真调试检查就能避免这样的漏洞(也正因为如此这种dll劫持的场景一般不会发生);如果不是我看了一眼程序的日志也不会有接下来这一系列有趣的发现。我还没有看到有人提过这些并且很有可能还有类似的没有被人发现的漏洞,同时也要提醒windows平台的开发者现在windows系统加载dll的机制仍不完善,注意确认自己的dll被正确加载。
0x02 时间线
2020-06-30 发现漏洞并报告给cisco PSIRT
2020-07-01 cisco PSIRT分配了PSIRT-0447917012
2020-07-10 cisco PSIRT没有能够成功复现,我提供了更多细节,强调只有用户成功登录之后才能触发漏洞
2020-07-15 cisco PSIRT确认
2020-08-05 cisco PSIRT告知漏洞会在8月27日发布的新版本中修复,9月2日发布安全公告
2020-08-19 cisco PSIRT希望能将发布安全公告的时间推迟到10月7日确保公开披露之前所有的用户能够升级到不受影响的版本
2020-10-07 cisco PSIRT发布安全公告