7

IE安全系列之——昨日黄花:IE中的ActiveX(I) | WooYun知识库

 6 years ago
source link:
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

IE安全系列之——昨日黄花:IE中的ActiveX(I)

IX.1 ActiveX的历史和简单的介绍


说到ActiveX,则不得不提到COM(组件对象模型)。COM出现时要解决的问题是,“能否把软件做到和硬件一样”,硬件的理想情况是比如有人规定了USB的规范,(Server)提供一个USB接口之后,(Client)只要正确实现了USB就可以让二者相联系,扩展出更多的功能(USB键鼠,U盘,摄像头,等等)。这之中Server(集线器)并不需要知道另一头Client(键盘?鼠标?)具体做啥的,只是知道我(Server)提供给你(Client)一个符合USB规范的接口,你(Client)弄上个东西连接成功就能用,至于你(Client)如何实现就不是我(Server)的事情了。

最初COM的出现也是为了解决类似的问题,例如我在IE里面如何打开一个WORD文档?针对它的解决方案称为OLE(对象连接与嵌入)。1993年微软发布了OLE2,在这(ole32.dll)中提供的API也被日后认为是COM API。有了这些支持之后,微软用它创造了OLE控件,并最终发展成为了在IE中常见的ActiveX控件。如果你用过VB的话,在VB里就能发现大量此类控件的身影,如内嵌的Microsoft Viso等等。

enter image description here

每个ActiveX控件都由一个GUID(全局唯一标识符)来标识自己,GUID和UUID(全球唯一标识符)差不多,只不过后者是OSF(开源软件基金会)维护,前者是微软自己的实现。

GUID是一个128位的数字,理论上是极大概率时间空间唯一的(随机数生成的空间有2122的大小,按照类似生日问题的算法,如果正确生成的话,和其他人生成的偶然重复概率为1/261)。

GUID算法包括1490年开始到现在的分钟数(保证时间唯一性),一个伪随机数,和MAC地址(保证空间唯一性,没有网卡的话会使用另一个随机常量),API CoCreateGuid可以生成GUID。GUID的一般形式类似于{AFEE063C-05BA-4248-A26E-168477F49734}这样。

在IE里或者WSF或者HTA等支持OBJECT标签的地方,可以通过它来加载ActiveX,OBJECT标签的具体用法请见参考资料(1)。

enter image description here

图:iDefense ComRaider ActiveX Fuzzer生成的WSF测试脚本使用了Object标签来载入被测ActiveX控件

IX.2 IE中的ActiveX


默认情况下,要在IE浏览器中运行ActiveX插件,ActiveX插件必须同时拥有Safe For Scripting/Safe For Init标记才可以运行。在IE发现HTML网页中有ActiveX控件时,IE会依次检查如下动作来确定控件是否可以安全加载和运用于代码中。

(1) IE会先检查ActiveX控件是否设置了killbit,如果设置了Killbit,IE将不会加载这个控件;

(2)IE会确定这个控件是否派生了IObjectSafety,如果有的话,IE会通过这个接口检查是否有设置Safe for Scripting/Safe For Init,如果没有派生IObjectSafety,IE会在注册表检查{7DD95802-9882-11CF-9FA9-00AA006C42C4} (Safe for Initialization){7DD95801-9882-11CF-9FA9-00AA006C42C4}(Safe For Scripting).两项。

这里的具体内容在之前的一篇文章http://drops.wooyun.org/papers/5673有介绍,所以不重复叙述了。为了后续实验方便,我们可以使用环境自己先弄个ActiveX,这里以Microsoft Visual C++ 2010为例创建一个ActiveX控件。

首先,如图创建一个新工程,简单起见,在后一个窗口直接完成即可。

enter image description here

生成的对外接口定义文件(XXX.idl)文件是和该控件信息有关的一个重要文件,许多信息都可以在此看到。例如“类信息”中uuid就是ActiveX控件待会儿在IE中加载时所要用到的Classid。

enter image description here

由于我们只是演示,因此我们简单的添加一个函数foo(): 在类视图的接口处点击右键,选择添加->方法

enter image description here

然后,添加一个void foo(),填写之后点击完成:

enter image description here

这时VS会在多个地方添加这个函数的信息,不过简单起见,回到刚才的idl文件中我们就可以看到添加了个新函数

enter image description here

在MSVC中直接F12过去:

enter image description here

这个位置就是新加函数的位置,为了方便演示,我们在里面随便弹一个对话框好了:

::MessageBox(0, L"hello wooyun", L"blast", MB_OK);

然后,我们右键选择工程,编译一个Release版的ocx控件:

enter image description here

之后,使用regsvr32 testActivex.ocx。

enter image description here

此时,该ActiveX就已经被注册了,我们创建一个测试用的htm文件吧,

<HTML>    
<OBJECT ID="test" WIDTH=300 HEIGHT=300 classid="CLSID:2D9835F7-9534-46C2-AE7A-C75098AA6105">  
</OBJECT>  
</HTML>  

CLSID请换成你的idl里面的那个uuid。由于我们的ActiveX控件并未设置Safe For Scripting和Safe For Init,所以在本地域打开时IE做了这个提示,点击是之后,就可以看到插件运行起来了。

enter image description here

enter image description here

此时,我们也可以测试调用我们加入的foo()函数,在SCRIPT标签中调用test.foo(),即可调用成功,可见IE中弹出了一个对话框:

enter image description here

要实现Safe For Scripting、Init,请这么做: 头文件(例如我的工程是testActivexCtrl.h)中加入#include <objsafe.h>,然后将 DECLARE_INTERFACE_MAP()

#!c++
BEGIN_INTERFACE_PART(ObjSafe, IObjectSafety)   


    STDMETHOD_(HRESULT,   GetInterfaceSafetyOptions)   (     
    /*   [in]   */   REFIID   riid,   
    /*   [out]   */   DWORD   __RPC_FAR   *pdwSupportedOptions,   
    /*   [out]   */   DWORD   __RPC_FAR   *pdwEnabledOptions   
    );  

    STDMETHOD_(HRESULT,   SetInterfaceSafetyOptions)   (     
        /*   [in]   */   REFIID   riid,   
        /*   [in]   */   DWORD   dwOptionSetMask,   
        /*   [in]   */   DWORD   dwEnabledOptions   
        );  

END_INTERFACE_PART(ObjSafe);

加入class CtestActiveXCtrl : public COleControl块中。

在对应CPP文件的最后加入下列代码,记得将CtestActiveXCtrl换成你自己的类名。

#!c++
BEGIN_INTERFACE_MAP(CtestActiveXCtrl,COleControl) 
  INTERFACE_PART(CtestActiveXCtrl,IID_IObjectSafety,ObjSafe) 
END_INTERFACE_MAP()  

ULONG FAR EXPORT CtestActiveXCtrl::XObjSafe::AddRef() 
{ 
  METHOD_PROLOGUE(CtestActiveXCtrl,ObjSafe) 
    return pThis->ExternalAddRef(); 
}  

ULONG FAR EXPORT CtestActiveXCtrl::XObjSafe::Release() 
{ 
  METHOD_PROLOGUE(CtestActiveXCtrl,ObjSafe) 
    return pThis->ExternalRelease(); 
}  

HRESULT FAR EXPORT CtestActiveXCtrl::XObjSafe::QueryInterface(REFIID iid,void FAR* FAR* ppvObj) 
{ 
  METHOD_PROLOGUE(CtestActiveXCtrl,ObjSafe) 
    return (HRESULT)pThis->ExternalQueryInterface(&iid,ppvObj); 
}  

const DWORD dwSupportedBits = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA; 
const DWORD dwNotSupportedBits=~dwSupportedBits;  

HRESULT STDMETHODCALLTYPE   
  CtestActiveXCtrl::XObjSafe::GetInterfaceSafetyOptions(   
  /*[in]*/ REFIID riid, 
  /*[out]*/ DWORD __RPC_FAR *pdwSupportedOptions, 
  /*[out]*/ DWORD __RPC_FAR *pdwEnabledOptions) 
{ 
  METHOD_PROLOGUE(CtestActiveXCtrl,ObjSafe) 
    HRESULT retval = ResultFromScode(S_OK); 

  IUnknown FAR* punkInterface; 
  retval = pThis->ExternalQueryInterface(&riid, (void **)&punkInterface); 
  if(retval != E_NOINTERFACE) 
  { 
    punkInterface->Release(); 
  } 

  *pdwSupportedOptions=*pdwEnabledOptions=dwSupportedBits; 
  return retval; 
}  

HRESULT STDMETHODCALLTYPE   
  CtestActiveXCtrl::XObjSafe::SetInterfaceSafetyOptions(   
  /*[in]*/ REFIID riid, 
  /*[in]*/ DWORD dwOptionSetMask, 
  /*[in]*/ DWORD dwEnabledOptions) 
{ 
  METHOD_PROLOGUE(CtestActiveXCtrl, ObjSafe) 

   IUnknown FAR* punkInterface; 
  pThis->ExternalQueryInterface(&riid, (void **)&punkInterface); 
  if(punkInterface)
  { 
    punkInterface->Release(); 
  } 
  else 
  { 
    return ResultFromScode(E_NOINTERFACE); 
  }  

  if(dwOptionSetMask & dwNotSupportedBits)  
  {   
    return ResultFromScode(E_FAIL); 
  }  

  dwEnabledOptions&=dwSupportedBits; 
  if((dwOptionSetMask&dwEnabledOptions)!=dwOptionSetMask) 
  { 
    return ResultFromScode(E_FAIL); 
  } 

  return ResultFromScode(S_OK); 
}

重新编译,再次打开IE时,这个控件就会直接加载起来而不会再弹出对话框了。

IX.3 Windows 10中ActiveX插件变成了什么样


另一个大家比较关注的可能是Windows 10里面的ActiveX情况,有一个好消息是Microsoft Edge已经不支持ActiveX了,不过Windows 10同样自带的IE11则依然和Win7、Win8的IE11一样,继续支持ActiveX。

在Windows 10中让我们做同样的事情,

enter image description here

首先,Win10提供了IE和Edge浏览器,选择使用Edge浏览器打开时,页面中并未加载该ActiveX控件:

enter image description here

可以看到test对象事实上只是一个CObjectElement而已,它并没有加载ActiveX控件。使用工具查看Edge的内存也可得出同样结论——这个OCX并没加载到内存。

enter image description here

enter image description here

再换用IE打开这个页面,在Win10自带的IE11中,我们看到插件正常运行了。

enter image description here

另外,在原先的IE中,Flash插件也是靠ActiveX的形式活着的。在Edge中应该也考虑到了这个问题,Edge自带一套Flash,所以用户不需要额外去网站上下载安装,这套Flash的形式是什么呢?我们可以简单看一下:

enter image description here

首先我们可以看到FLASH的加载代码依然和之前一样,采用Object的方式加载:

enter image description here

不过之前的经历我们知道Object在Edge中是不能像之前一样简单加载ActiveX的,那这里是什么呢?参考进程列表可以发现,Edge在执行到包含有Flash的页面时,会启动一个FlashUtil_ActiveX.exe 进程,这个进程名字十分奇怪,在仔细查看Edge的进程模块后,我们可以发现,Edge其实还是保留着加载ActiveX控件的能力的,只不过控制在一个比较小的范围内而已:

enter image description here

enter image description here

本章节只是介绍了ActiveX的历史和一个示例ActiveX的编译方法,而并没有介绍有关Activex安全的部分,关于Activex漏洞的挖掘等内容将在后续章节介绍。

参考资料


(1] http://www.w3school.com.cn/tags/tag_object.asp

(2] http://www.ffri.jp/assets/files/monthly_research/MR201503_Windows_10_Technical_Preview_Security_Overview_ENG.pdf


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK