CVE-2017-8464(stuxnet 3.0) 分析

0xFF 前言

​以前大一听网络安全宣讲会的时候,听他们讲那个震网事件,说插一个U盘就可以在用户不知情的情况下执行任意代码,之前一直都没有搞懂到底是怎么做到的,所以现在就来尝试来分析分析。这里要分析的cve-2017-8464是一个LNK文件漏洞,控制面板快捷方式加载CPL的时候存在缺陷导致可以加载指定DLL,从而执行任意代码。

0x00 分析工具

  • IDA
  • WinHex
  • WINDBG
  • windows 7 sp1 x86 (no patch)

0x01 漏洞复现

1)、生成一个DLL用于测试

编写一个测试DLL,为了看到效果,就弹一个MessageBox吧。

#include<Windows.h>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
if(dwReason == DLL_PROCESS_ATTACH)
MessageBox(0, TEXT("Called me!"), TEXT("Cap"), 0);
return TRUE;
}

将生成的DLL名字改为a.dll,并将其放在漏洞机中的C盘根目录下。

2)、构造一个恶意的lnk二进制文件

使用winhex创建并编辑一个如下图数据的LNK文件(后缀为.lnk)。并将其放在任意的地方(我放的是桌面)

CVE-2017-8464 分析-LMLPHP

3)、RUA!

​ok,现在刷新一下桌面,wow!,会弹超多次的对话框。

CVE-2017-8464 分析-LMLPHP

0x02 POC细节

CVE-2017-8464 分析-LMLPHP

CVE-2017-8464 分析-LMLPHP

CVE-2017-8464 分析-LMLPHP

0x03 分析

1)、bp LoadLibraryW

​大概率是explorer.exe解析的,所以用windbg双机调试,下条件断点。(为了便于调试,请先将那个a.dll中调用MessageBox那行注释掉,重新编译生成新的a.dll放于漏洞机的C盘根目录)。

  • 先使用!process 0 0 找到 explorer.exe 的EPROCESS 假设为 8781f510

  • 断到指定进程环境下.process -i -r -p 8781f510

  • 使用条件断点:bp Kernel32!LoadLibraryW "$<C:\\windbgScript\\sp.txt"

sp.txt文件内容(绝对路径:C:\windbgScript\sp.txt)

as /mu ${/v:dllname} poi(esp+4)
.if ($sicmp( "${dllname}", "C:\a.dll")=0) {.echo ${dllname}} .else {gc}

如果下不了断点请先使用这个命令再加载下符号: !sym noisy;.reload /user *,再检查下绝对路径是否是使用的\\(双斜线),windbg符号路径是否已经设置。

  • 下好断点后,键入g命令运行,漏洞机中刷新桌面.windbg 断下:

    显示如下内容:

  • 好,查看栈回溯

    看到SHELL32!CShellLink::_LoadFromFile,猜测是从这个函数开始解析lnk文件的。使用lm v m shell32

    命令查看得到shell32.dll的在漏洞机中的路径:

    ok,找到shell32.dll 并把它拖进IDA pro中,开始我们的F5"逆向分析"

2)、Parse 恶意lnk文件的过程

CShellLink::_LoadFromStream

在CShellLink::_LoadFromStream中,首先会读取恶意lnk文件头4个字节,判断是不是等于0x4C。接着读取恶意lnk文件头+0x4处(读取文件流会造成文件指针移动,刚刚已经读了4个了,所以下一次开始读取时文件指针偏移加4)继续读取恶意lnk文件ShellLinkHeader结构的剩下0x48个字节的数据并放到this->offset_0n244处(这个this就是CShellLink这个对象的实例),接着判断LinkCLSID(16 bytes)是否等于00021401-0000-0000-C000-000000000046.

CVE-2017-8464 分析-LMLPHP

​之后取LinkFlags 检查有哪些结构在ShellLinkHeader后面存在,首先检查的是HasLinkTargetIDList ,在我们构造这个POC中,是成立的。(pCShellLink+244+16 就是LinkFlags,因为this->offset_0n244处存的是ShellLinkHeader结构剩下的的0x48字节,LinkCLSID后面紧跟着的就是LinkFlags字段,16是LinkCLSID的大小)。下图中的v6会等于0,所以会调用CShellLink::_LoadIDList,通过逆向(F5)这个函数得知做的功能是分配一块内存加载lnk文件的LINKTARGET_IDLIST段(去掉这个段的前2个字节,即ItemID[0]+ItemID[1]+ItemID[2])到this->0n188处。这个函数执行后,当前文件流指针就指向了LINKTARGET_IDLIST的后面,对于我们这个POC来说也就是EXTRA_DATA段了。

CVE-2017-8464 分析-LMLPHP

​接着从文件流读取EXTRA_DATA到this->offset_0n228处。

CVE-2017-8464 分析-LMLPHP

​下面那个是DWORD*的this+47,所以要乘以4即this->offset_0n188,即判断是不是存在LinkTargetIDList.IDList,我们这个POC是存在的,所以调用CShellLink::_DecodeSpecialFolder(this);

CVE-2017-8464 分析-LMLPHP

CShellLink::_DecodeSpecialFolder(CShellLink *this)

首先调用SHFindDataBlock查找this->offset_0n228处(EXTRA_DATA)是否有KnownFolderDataBlock(它的BlockSignature 是0xA000000B),显然我们的POC中没有构造这个Block。所以27行的v2会返回0,接着会执行第41行,调用SHFindDataBlock查找this->offset_0n228处(EXTRA_DATA)是否有SpecialFolderDataBlock(它的BlockSignature是0xA0000005),而我们的POC中的确存在这个Block,所以SHFindDataBlock返回指向SpecialFolderDataBlock的指针。

接着取pSpecialFolderDataBlock->SpecialFolderID(偏移为8)作为SHCloneSpecialIDList函数的第二个参数,根据MSDN上关于SHCloneSpecialIDList的介绍,它是用来获取一个KnownFolder的ITEMIDLIST结构,我们poc中构造的是3,

在vs中查看得知3对应的是Control Panel,所以这个函数返回的是一个指向Control Panel的ITEMIDList结构的指针(这个是个关键,详细的请看后面我单独会写)。

CVE-2017-8464 分析-LMLPHP

CVE-2017-8464 分析-LMLPHP

接着会调用TranslateAlias函数,传入的参数分别是:

  • this->offset_0n188,即ItemID[0],ItemID[1],ItemID[2]
  • v11 是指向一块存放 ItemID[0]和ItemID[1]的内存
  • 控制面板的ITEMIDLIST,用于之后绑定

CVE-2017-8464 分析-LMLPHP

TranslateAlias

CVE-2017-8464 分析-LMLPHP

TranslateAliasWithEvent

SHBindToObject函数MSDN上是有介绍的:

所以要触发到后面调用CControlPanelFolder::的例程,那么一定要获取到ControlPanel的IDList

CVE-2017-8464 分析-LMLPHP

ReparseRelativeIDList

58行的调用也是个关键,是调用这个将poc中IDList[2]中的"C:\a.dll" 加载到CControlPanelFolder:

04-16 20:40