ISS_ Prism_ _ Linux - Azimuth Security_1_ by pptfiles

VIEWS: 0 PAGES: 71

									Attacking Interoperability



July 2009
    INTRODUCTION


2
     Thesis
      - The added complexity of expanded interoperability creates subtle, new, and
        interesting opportunities for attackers
         • Large, nuanced attack surface
         • Speech targets browser components, but ideas applicable elsewhere

     Overview
      - Part I – The attack surface
      - Part II – Vulnerability classes and results


     We will uncover subtle vulnerability classes present in all major
      web browsers!




3
    ATTACK SURFACE


4
    Interoperability:
     A Large Attack Surface
     - Scriptable plugins
     - Communications and
       marshalling
     - Language and DOM
       runtimes

     Unique bug classes
     - Object Retention
     - Type confusion
     - Transitive Trust



5
    Map of the Modern Web Browser




6
     Scriptable Plugins can be targeted via well-known entry points
      - Experienced a lot of scrutiny (ActiveX fuzzers etc, eg: )
      - Well-known bug classes exploited often – useful, but boring
      - Type manipulation and lifespan of parameters – interesting

     Communications layers are a large attack surface
      - Charged with converting data from one representation to another
      - Dealing with complex objects
      - Marshalling / Serialization

     DOM and Language runtimes
      - Lots of native code to target
      - Have to deal with same type manipulation / lifespan issues as plugins



7
     Two major competing technologies
      - Microsoft ActiveX
      - Mozilla NPAPI (Firefox, Safari, Chrome, Opera, the list goes on)

     ActiveX
      - Plugin registration
      - COM Stuff
         • Automation objects
         • Persistent Streams
      - Data manipulation (VARIANTs and related APIs)

     NPAPI
      - Plugin Registration
      - NPAPI / NPRuntime
      - Data manipulation (NPObject / NPClass usage)

8
    ACTIVEX


9
      Everyone knows what ActiveX controls are
       - Registered in HKCR\CLSID\{<CLSID>}
      Safe for Initialization (SFI) vs Safe For Scripting (SFS)
       - SFI: Instantiation from persistent COM stream
       - SFS: Control can be scripted
      Dangerous controls can also be killbitted
       - HKLM\Software\Microsoft\Internet Explorer\ActiveX Compatibility (0x400)
       - IE8: Per-user killbitting possible:
         HKCU\Software\Microsoft\Windows\CurrentVersion\Ext\Settings\{CLSID}
         (Flags value = 1)
      Pre-approved list of controls added to IE7+
       - HKLM\Software\Microsoft\Windows\CurrentVersion\Ext\PreApproved
       - No prompting for these controls
       - IE8: controls can be pre-approved per-user and per-domain
       - HKCU\Software\Microsoft\Windows\CurrentVersion\Ext\Stats\{CLSID}\iexplor
         e\AllowedDomains
10
      IE8 GUI shows available controls
       - Takes all the registry work out




11
      ActiveX controls and scriptable objects are IDispatch /
       IDispatchEx COM objects
       - Self-publishing
       - Methods / properties called via Invoke() function using DispID
       - Parameters passed in DISPPARAMS structure
       - Essentially array of VARIANTARGS

      typedef struct FARSTRUCT tagDISPPARAMS {
             VARIANTARG FAR* rgvarg;               //   Array of arguments.
             DISPID FAR* rgdispidNamedArgs;        //   Dispatch IDs of named arguments.
             unsigned int cArgs;                   //   Number of arguments.
             unsigned int cNamedArgs;              //   Number of named arguments.
      } DISPPARAMS;




12
      VARIANT data structure used to represent data types
       - Data structure with type variable (vt) and value variable (union)
       - Types consist of basic type (0 -> 0xFFF) + possible modifiers (0x1000+)
       - VT_BYREF modifier not mutually exclusive with other modifiers
     Type Name                 Value                     Union Contains
     VT_EMPTY                  0x0000                    Undefined
     VT_NULL                   0x0001                    NULL value
     VT_I4                     0x0003                    Signed (4-byte) integer
     VT_BSTR                   0x0008                    String; Pointer to a BSTR
     VT_DISPATCH               0x0009                    Pointer to an IDispatch interface
                                                         (automation object)

     VT_BOOL                   0x000B                    Boolean (2-byte short)
     VT_VARIANT                0x000C                    Pointer to another VARIANT
     VT_UNKNOWN                0x000D                    Pointer to an IUnknown interface (any
                                                         COM object)



     Modifier Name             Modifier Value             Value
     VT_VECTOR                 0x1000                     Value points to a simple counted
                                                          array (Rarely used)
     VT_ARRAY                  0x2000                     Value points to a SAFEARRAY
                                                          structure
     VT_BYREF                  0x4000                     Value points to base type, instead
                                                          of containing a literal of the base
                                                          type

13
     COM serialization
      - Accessed via COM
        interfaces
        •IStream and IStorage
      - Represents a file /
        memory stream / etc
      - Support persistence by
        implementing one of the
        IPersist interfaces




14
       COM persist streams contain binary data representing object
        properties
         - Interpretation depends on the IPersist*::Load() method
         - Most use default ATL IPersistStream::Load() template method
         - Programmer just needs to define a property map of the object
         - Property maps are structures, simplified definition using macros
           (BEGIN_PROPERTY_MAP(), BEGIN_PROP_MAP(), PROP_ENTRY(),
           PROP_ENTRY_EX(), PROP_DATA_ENTRY(), etc..)
     struct ATL_PROPMAP_ENTRY
     {
                 LPCOLESTR szDesc;
                 DISPID dispid;
                 const CLSID* pclsidPropPage;
                 const IID* piidDispatch;
                 DWORD dwOffsetData;
                 DWORD dwSizeData;
                 VARTYPE vt;
     };

15
     class HelloCom :
                 public IPersistStreamInitImpl<HelloCom>,
                 public IPersistStorageImpl<HelloCom>,
                 public IPersistPropertyBagImpl<HelloCom>,
      {
     public:
     BEGIN_PROP_MAP(HelloCom)
                 PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
                 PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
                 PROP_ENTRY("NameFirst", 1, CLSID_HelloComCtrl)
                 PROP_ENTRY_TYPE("NameLast", 2, CLSID_HelloComCtrl, VT_BSTR)
     END_PROP_MAP()
     };




 Offset          Hexadecimal representation of bytes                   Description
 0x00            00 09 00 00                                           Version nine of the ATL
 0x04            00 01 00 00                                           The _cx value is 256
 0x08            00 01 00 00                                           The _cy value is 256
 0x0C            08 00                                                 NameFirst is stored as a VT_BSTR
 0x0E            0C 00 00 00                                           NameFirst is 12 characters long
 0x12            46 00 69 00 72 00 73 00 74 00 00 00                   NameFirst is equivalent to "First"
 0x1E            0A 00 00 00                                           NameLast is 10 bytes long
 0x22            4C 00 61 00 73 00 74 00 00 00                         NameLast is equivalent to "Last"

16
      COM persistent streams embeddable in IE
          - Property Bags (Textual strings using <PARAM> tags)
          - Binary files retrieved from “data” parameter of <OBJECT> tag
            • .ICA, .STM, .ODS extensions -> IPersistStream
            • Otherwise, query for all COM IPersist* interfaces



     <OBJECT
                id="VIDEO"
                CLASSID="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6"
                data="./persistence_data"
                type="application/x-oleobject"
     />




17
      Most COM components use the ATL (Better than Madoff)




18
     NPAPI / NPRUNTIME


19
      Plugins registered in one of two ways
       - Copied into the plugins directory of the browser (eg. C:\Program Files\Mozilla
         Firefox\plugins)
       - Registry key added (for Firefox: HKLM\Software\MozillaPlugins)

      Registered plugins are associated with content types
       - Content handled by a plugin is defined as 1 or more MIME types
       - Can also be associated with 1 or more file extensions
       - Information for both is in the “Version” information of the DLL




20
      URL “about:config” shows all the relevant information




21
      NPAPI is divided into two parts
       - Browser-side functions
       - Plugin-Side functions

      Browser-side functions provide browser services to the plugin
       - Accessed via NPNetscapeFuncs structure passed to plugin
       - By convention, functions are prefixed with NPN_*
         • Example: NPN_Evaluate(), NPN_GetURL(), etc

      Plugin-side functions provide plugin implementation to the
       browser
       - Accessed via NPPluginFuncs structure returned by plugin
       - By convention, functions are prefixed with NPP_*
         • Example: NPP_New(), NPP_Destroy(), etc



22
      Scriptable objects exposed to the browser via NPP_GetValue()
       - Called with NPPVpluginScriptableNPObject
      Scriptable objects are instances of NPObjects
       - Contains reference count + NPClass to define behaviour
     struct NPClass
     {
         uint32_t structVersion;
         NPAllocateFunctionPtr allocate;
         NPDeallocateFunctionPtr deallocate;
         NPInvalidateFunctionPtr invalidate;
         NPHasMethodFunctionPtr hasMethod;
         NPInvokeFunctionPtr invoke;
         NPInvokeDefaultFunctionPtr invokeDefault;
         NPHasPropertyFunctionPtr hasProperty;
         NPGetPropertyFunctionPtr getProperty;
         NPSetPropertyFunctionPtr setProperty;
         NPRemovePropertyFunctionPtr removeProperty;
         NPEnumerationFunctionPtr enumerate;
         NPConstructFunctionPtr construct;
     };


23
      NPObjects support getting/setting properties
       - HasProperty(), GetProperty(), SetProperty() exposed by NPClass
      Also supports method invocation
       - HasMethod(), Invoke()
       - InvokeDefault() used when object is invoked like a property




24
      Variables passed to/from JS as NPVariants
       - Simple type/value structure
       - Value is a union, much like Microsoft VARIANT structures
         • No composite types
       typedef struct _NPVariant {
           NPVariantType type;
           union {
               bool boolValue;
               int32_t intValue;
               double doubleValue;
               NPString stringValue;
               NPObject *objectValue;
           } value;
       } NPVariant;


       - Manipulated with simple macros provided by npruntime.h
         • NPVARIANT_TO_XXX(), XXX_TO_NPVARIANT(), NPVARIANT_IS_XXX()


25
      Javascript objects are wrapped as NPObjects by the marshalling
       layer, and vice versa
       - Not particularly important, but we drew this cool diagram




26
     VULNERABILITY CLASSES &
     RESULTS

27
      Interoperability layers affected by standard bug classes
       - Buffer overflows (Boring)
       - Memory Corruption (Boring)

      Additional complexities
       - Language agnostic variable representation
       - Lifespan of data
       - Security models

      Unique challenges result in unique vulnerabilities
       - Object retention vulnerabilities
       - Type confusion vulnerabilities
       - Transitive trust vulnerabilities



28
     OBJECT RETENTION


29
      Data structures shared between multiple components
       - Individual components unaware of other components utilizing an object
       - Need to ensure memory is released, but not too early

      Strategy: reference counting
       - Objects contain a reference count variable
       - Consumers increment reference count to ensure object is retained in
         memory
       - Reference count decremented when the consumer no longer needs the
         object

      Mis-management of reference counting is bad news!




30
      Types of life span mismanagement
       - Releasing: Not maintaining a reference when it is still required
       - Not releasing: Maintaining a reference when it is no longer required

      Consequences depend on nature of mis-management discovered
       - Memory is deallocated too early
          • Uses heap data as vtable pointers
          • Double frees
          • Misc. Memory Corruption
       - Memory is maintained indefinitely
          • Memory leaks (Heap littering)
          • Potentially results in memory being deallocated too early

      Object retention APIs differ between ActiveX and NPAPI


31
      Internally, the reference count is stored as a 32-bit integer
       - 0xFFFFFFFF + 2 references = 1 Reference
       - 1 Reference, once Release()’d will cause stale pointers

      Effectively resulting in the same effect as releasing a reference
       when one is required

      Slightly more difficult to exploit
       - Takes time, done incorrectly can freeze the browser

      Takeaway:
       - Any miscounting can be beneficial to an attacker




32
      COM Objects manage object retention with the IUnknown interface
       - IUnknown::AddRef()
       - IUnknown::Release()

      Receiving a COM object as a parameter
       - Must call AddRef() if you intend to retain the object
       - Must call Release() when you are finished with it




33
      Example I
       - No reference to object retained!


            HRESULT CMyObject::put_MyProperty(IDispatch *pCallback)
            {
                     m_pCallback = pCallback;
                     return S_OK;
            }

            HRESULT CMyObject::get_MyProperty(IDispatch **out)
            {
                     if(out == NULL || *out == NULL || m_pCallback == NULL)
                               return E_INVALIDARG;

                     *out = m_pCallback;
                     return S_OK;
            }




34
      Example II
       - Release() is never called when object is assigned
            HRESULT CMyObject::put_MyProperty(IDispatch *pCallback)
            {
                     if(pCallback == NULL)
                               return E_INVALIDARG;

                     pCallback->AddRef();
                     m_pCallback = pCallback;
                     return S_OK;
            }
            HRESULT CMyObject::get_MyProperty(IDispatch **out)
            {
                     if(out == NULL || *out == NULL || m_pCallback == NULL)
                               return E_INVALIDARG;

                     *out = m_pCallback;
                     return S_OK;
            }

35
      Example III
       - Object released, but not referenced when returned by the get_ function!
            HRESULT CMyObject::put_MyProperty(IDispatch *pCallback)
            {
                     if(pCallback == NULL)
                               return E_INVALIDARG;
                     if(m_pCallback != NULL)
                               m_pCallback->Release();
                     pCallback->AddRef();
                     m_pCallback = pCallback;
                     return S_OK;
            }
            HRESULT CMyObject::get_MyProperty(IDispatch **out)
            {
                     if(out == NULL || *out == NULL || m_pCallback == NULL)
                               return E_INVALIDARG;

                     *out = m_pCallback;
                     return S_OK;
            }
36
      VARIANTs also need to be handled with care
       - VARIANTs containing pointers need to be handled carefully
       - Copying pointers leads to multiple pointers pointing to the same location
       - What if it gets freed?

      Shallow copying versus Deep Copying
       - Pointer values shouldn’t be copied – the target object should be duplicated
       - COM interfaces: AddRef() called on object
       - Strings / Arrays / etc: clone the memory object
       - VariantCopy() and VariantCopyInd() handle duplication correctly

      Shallow copying – how does it happen?
       - Using memcpy() instead of a VARIANT API function




37
      Example IV
       - memcpy() considered dangerous (use memcpy_s()?)
          HRESULT CMyObject::put_MyProperty(VARIANT src)
          {
                   HRESULT hr;
                   memcpy((void *)&m_MyProperty, (void *)&src, sizeof(VARIANT));

                    return S_OK;
          }

          HRESULT CMyObject::get_MyProperty(VARIANT *out)
          {
                   HRESULT hr;

                    if(out == NULL)
                             return E_FAIL;
                    VariantInit(out);

                    memcpy(out, (void *)&m_MyProperty, sizeof(VARIANT));

                    return S_OK;
          }

38
      I used VariantCopy() instead of memcpy() – safe?
       - Short answer: possibly

      VariantCopy() vs VariantCopyInd()
       - VariantCopy() does not follow VT_BYREF indirection
       - VariantCopyInd() does (VT_BYREF|VT_VARIANT recursion not allowed)

      VariantCopy() is potentially unsafe when VT_BYREF is set!
       - If VT_BYREF is set, VariantCopy() == memcpy() (shallow)
       - Exploitable? Depends on what happens to the VARIANT afterwards…

      Additional note: VariantCopyInd() is never used when a
       SAFEARRAY is duplicated with SafeArrayCopy()!



39
      Example V
       - VariantCopy() is used – what if we have a VT_BYREF?
          HRESULT CMyObject::put_MyProperty(VARIANT src)
          {
                     HRESULT hr;
                     VariantInit(&m_MyProperty);

                    hr = VariantCopy(&m_MyProperty, &src);
                    if(FAILED(hr))
                               return hr;
                    return S_OK;
          }
          HRESULT CMyObject::get_MyProperty(VARIANT *out)
          {
                     HRESULT hr;
                     if(out == NULL)
                                return E_FAIL;
                     VariantInit(out);
                     hr = VariantCopy(out, &m_MyProperty);
                     if(FAILED(hr))
                                return hr;
                     return S_OK;
          }
40
      Similar story for NPObjects
       - NPN_RetainObject() increments reference count
       - NPN_ReleaseObject() decrements count (and possibly frees object)

      Retaining objects without NPN_RetainObject() is bad
       - Object will possibly be freed

      Obviously memcpy()’ing NPVariants is also potentially dangerous
       - Can be equated to memcpy() of a VARIANT
       - In practice this is rare…

      Handing out objects in GetProperty() also requires retaining the
       object!



41
      Example VI
       - Object retained without adding a reference, potential stale pointer issues

          bool SetProperty(NPObject *obj, NPIdentifier name, const NPVariant
          *variant)
          {
                    if(name == kTestIdent)
                    {
                             if(!NPVARIANT_IS_OBJECT(*variant))
                                       return false;

                             gTestObject = NPVARIANT_TO_OBJECT(*variant);
                             return true;
                    }
                    return false;
          }




42
      Failure to release objects has similar problems as in ActiveX
       - Memory leaks
       - Possible stale pointer issues due to integer overflow

      Objects must be released with NPN_ReleaseObject()




43
      Example VII
       - Object retained without adding a reference, potential stale pointer issues

      bool SetProperty(NPObject *obj, NPIdentifier name, const NPVariant *variant)
      {
                 if(name == kTestIdent)
                 {
                            if(!NPVARIANT_IS_OBJECT(*variant))
                                        return false;

                             gTestObject = NPN_RetainObject(NPVARIANT_TO_OBJECT(*variant));

                             return true;
                 }
                 return false;
      }




44
     TYPE CONFUSION


45
      Interoperability requires language agnostic data representation
       - Contrived types
       - COM: VARIANT/VARIANTARG
       - NPRuntime: NPVariant


      Contrived types require careful programming
       - Big opportunity!



      Vulnerabilities occur when one data type is mistaken for another.
       - Type Wildcards
       - Unions




46
      Type Wildcards
       - Allow a wide range of types to be used for a variable
       - In C, they negate casting requirements
       - void *


      If the compiler doesn’t emit a warning, a programmer might not
       care
       - Requires more diligence to use properly


      Solution: ban void *
       - Not really.




47
      Normally the compiler protects against incorrect types
       - unsigned long *pulValue; char *szSource; strcpy(pulValue, szSource);
       - error C2664: 'strcpy' : cannot convert parameter 1 from 'unsigned long *' to
         'char *‘
       - warning: passing argument 1 of 'strcpy' from incompatible pointer type
      Sometimes it doesn’t
       - unsigned long pulValue[4]; char szSource[16]; memcpy(pulValue, szSource,
         sizeof(szSource));
       - 0 error(s), 0 warning(s)
       - gcc –Wall –o sample sample.c: no output
      Areas where types aren’t resolved can be exposed to attack
       - Memory corruption
       - Information leaks
       - Etc.


48
      Example I
       - The infamous ATL (vidctl) bug
                   SAFEARRAYBOUND rgsaInBounds;
                   SAFEARRAYBOUND rgsaBounds;
                   SAFEARRAY *saBytes;
                   void *pvData;

                   hr=pStream->Read(&saInBounds, sizeof(saInBounds), NULL);
                   if(hr<0||hr==1)
                       return(hr);

                   rgsaBounds.cElements = rgsaInBounds.cElements;
                   rgsaBounds.lLbound = 0;
                   saBytes = SafeArrayCreate(VT_UI1, 1, rgsaBounds);
                   if(saBytes == NULL)
                       return(E_OUTOFMEMORY);

                   hr = SafeArrayAccessData(saBytes, &pvData);
                   if(hr < ERROR_SUCCESS)
                       return(hr);

                   hr=pStream->Read(&pvData, rgsaInBounds.cElements, NULL);
                   ...



49
      Unions
       - Same memory space – different types
       - Useful for conserving memory and abstracting data
       - No errors or warnings at compile time when accessing incorrect type


      Programmer must keep track of the appropriate member
       - High-level identifiers keep track
       - Easy to get wrong (APIs somewhat unintuitive at times)


      We will consider the two technologies separately
       - ActiveX
       - NPAPI


50
      VARIANT Type Confusion I - Permissive property maps
       - Property maps tell the ATL what types to serialize / resurrect
       - During resurrection, the array is traversed

      Some property map entry macros require a specific variant type
       - PROP_ENTRY_TYPE()
       - PROP_ENTRY_TYPE_EX()
       - PROP_DATA_ENTRY()

      Others are more permissive
       - PROP_ENTRY()
       - PROP_ENTRY_EX()
       - Any of the less permissive ones if passed VT_EMPTY as the type




51
      PROP_DATA_ENTRY() vs PROP_ENTRY_*()
      - Ability to write memory allocated for a property directly into the class
      - If passed-in type is VT_EMPTY, no type checking will be performed
      - Will bypass any sanitization that occurs in IDispatch




52
      VARIANT Type Confusion II – Misinterpreting types
       - vt contains basic type + modifiers

      Type interpretation is susceptible to subtle errors
       - Masking off all the modifiers
          • Just operating on the basic type
       - Action based on a specific modifier
          • Eg. VT_ARRAY is set, doesn’t mean the type is a SAFEARRAY!
       - Masking off specific modifiers
          • Losing information is bad




53
      Example II – Multiple Modifiers (Synthetic)
       - Checks if VARIANT is an array of integers: VT_ARRAY + (VT_I4 or VT_UI4)
       - VT_BYREF can be used in conjunction with VT_ARRAY!
       - Type confusion when dealing with (VT_BYREF|VT_ARRAY|VT_I4)
       - Treats a SAFEARRAY ** as a SAFEARRAY *
       SAFEARRAY *psa;
       ULONG *pValue
       // Test if object is an array of integers
       VARTYPE baseType = pVarSrc->vt & VT_TYPEMASK;
       if((baseType != VT_I4 && baseType != VT_UI4)
           || ((pVarSrc->vt & VT_ARRAY) == 0) )
                return -1;

       psa = pVarSrc->parray;

       // operate on SAFEARRAY
       SafeArrayAccessData(psa, &pValues);
       ...

54
       Example III – IEs core DOM marshalling
          - VT_ARRAY modifier is masked off!
     int VARIANTARGToCVar(VARIANT *pSrcVar, int *res, VARTYPE vt, PVOID outVar, IServiceProvider
     *pProvider, BOOL bAllocString)
     {
         VARIANT var;

        VariantInit(&var);
        if(!(vt & VT_BYREF))
        {
            // Type mismatch - attempt conversion
            if( (pSrcVar->vt & (VT_BYREF|VT_TYPEMASK)) != vt && vt != VT_VARIANT)
            {
                ... Try type conversion, die on failure ...
            }
            switch(vt)
            {
                case VT_DISPATCH:
                           *(PDISPATCH)outVar = pSrcVar->pdispVal;
                          break;

                ... Other types dealt with here ...
            }

55
      VARIANT Type Confusion III – Direct type manipulation
       - Setting the vt directly
       - Calling an API function, failure to check if it succeeds
       - Mainly a result of VariantChangeType()/VariantChangeTypeEx() failing

      Setting the type manually can have significant consequences
       - Type confusion if error isn’t detected
       - Possible type confusion even if error IS detected
          • VariantClear() will misinterpret erroneous type




56
      Example IV – Direct Type Manipulation (Synthetic)
     inline HRESULT CComVariant::ReadFromStream(IStream* pStream)
     {
                 HRESULT hr;
                 hr = VariantClear(this);
                 if (FAILED(hr))
                             return hr;
                 VARTYPE vtRead;
                 hr = pStream->Read(&vtRead, sizeof(VARTYPE), NULL);
                 if (hr == S_FALSE)
                             hr = E_FAIL;
                 if (FAILED(hr))
                             return hr;
                 vt = vtRead;
                 //Attempts to read fixed width data types here
                 CComBSTR bstrRead;
                 hr = bstrRead.ReadFromStream(pStream);
                 if (FAILED(hr))
                             return hr;
                 vt = VT_BSTR;
                 bstrVal = bstrRead.Detach();
                 if (vtRead != VT_BSTR)
                 {
                             hr = ChangeType(vtRead);
                             vt = vtRead;
                 }
                 return hr;
     }


57
      VARIANT Type Confusion IV - Initialization Errors
       - Operating on VARIANTs that are partially or totally uninitialized
       - VARIANT API lends itself to these types of problems

      VariantClear() on uninitialized VARIANTs considered dangerous!
       - Need to call VariantInit() first (or otherwise set vt to VT_EMPTY)
       - Easy to forget to initialize them!

      VARIANT API functions often VariantClear() their dst parameters
       - VariantCopy()
       - VariantCopyInd()
       - VariantChangeType()
       - VariantChangeTypeEx()



58
      Example V – Uninitialized VARIANTs (Synthetic)
       - var never initialized with VariantInit()
       - If read fails, VariantClear() called

      HRESULT MyFunc(IStream* pStream)
      {
          VARIANT var;
          IDispatch* pDisp;
          HRESULT hr;
          var.vt = VT_DISPATCH;

          hr = pStream->Read(pDisp, sizeof(IDispatch *), NULL);
          if(FAILED(hr)) {
                VariantClear(&var);
                return hr;
          }
          . . .
          return hr;
      }




59
      Example VI – VariantCopy Example (Synthetic)
       - VariantCopy() calls VariantClear() on dstVar
       - dstVar is uninitialized
       HRESULT MyFunc(IStream* pStream)
       {
           VARIANT srcVar;
           VARIANT dstVar;
           IDispatch* pDisp;
           HRESULT hr;
           srcVar.vt = VT_DISPATCH;
           dstVar.vt = VT_DISPATCH;

           hr = pStream->Read(pDisp, sizeof(IDispatch *), NULL);
           if(FAILED(hr)) {
                  //VariantClear(&var);
                  return hr;
           }
           else {
               srcVar.pdispVal = pDisp;
               hr = VariantCopy(&dstVar, &srcVar);
           }
           return hr;
       }


60
      NPRuntime uses NPVariant data structures
       - Also a language agnostic value representation scheme
       - Also potentially vulnerable to type confusion attacks

      Like COM VARIANTs, but:
       - No type modifiers
       - No Arrays / Pointers
       - No dynamic conversion APIs
       - Simpler

      NPAPI does NOT do type coersion!
       - NPVARIANT_TO_XXX() just accesses a union member
       - Programmers must validate each parameter with NPVARIANT_IS_XXX()



61
      Exmaple I – Type Verification Omission (Google Native Client)
       - No check if ‘variant’ is really an integer value
       - Type confusion attack possible

      bool Plugin::SetProperty(NPObject* obj,
                               NPIdentifier name,
                               const NPVariant* variant) {
        Plugin* plugin = reinterpret_cast<Plugin*>(obj);
        if (kHeightIdent == name) {
          plugin->height_ = NPVARIANT_TO_INT32(*variant);
          return true;
        …




62
      Example II – Object Type Confusion (Google Native Client)
       - Subtle variation on previous attack
       - NPObject received is verified, but cast to a derivative of NPObject
       - No way to know if reinterpret_cast is safe!

      static bool GetHandle(struct NaClDesc** v, NPVariant var) {
        if (NPVARIANT_IS_OBJECT(var)) {
          NPObject* obj = NPVARIANT_TO_OBJECT(var);
          UnknownHandle* handle = reinterpret_cast<UnknownHandle*>(obj);
          *v = handle->desc();
          return true;
        } else {
          return false;
        }
      }




63
      Example III – Argument Count Discrepancy (Synthetic)
       - For Invoke() argCount must also be verified correctly
       - Lack of proper sanitization leads to uninitialized memory access
       - Not really type confusion, but similar effects
      bool Invoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t
      argCount, NPVariant *result)
      {
               if(name == kTestFuncName)
               {
                         if(argCount != 2 &&
                        (!NPVARIANT_IS_INT32(args[0]) ||
                               !NPVARIANT_IS_STRING(args[1])))
                                   return false;
                         unsigned int length = NPVARIANT_TO_INT32(args[0]);
                         char *buffer = ExtractString(args[1]);
                         ... more code ...
               }
      }

64
     TRUST


65
      Browser has an evolutionary security architecture
       - Core security features
       - Adapted over time to meet changing needs / technologies

      Components become loopholes for altered security requirements
       - Previously secure components are now a security threat
       - Weren’t designed with new security features in mind




66
      Plugins provide additional
       complications
       - Functionality becomes useful for
         subverting security mechanisms
       - Plugins can load other objects

      Trust extension becomes
       transitive in nature
       - Browser explicitly trusts Plugin A,
         Plugin A trusts Object B
       - Browser inadvertently trusts Object B




67
      Example – killbits and ActiveX
       - Only allows instantiation of certain ‘safe’ COM objects
       - Many controls are vulnerable just by instantiating them
       - Fix: Killbit them
     GUID                                   File
     47C6C527-6204-4F91-849D-66E234DEE015   Srchui.dll
     35CEC8A3-2BE6-11D2-8773-92E220524153   Stobject.dll
     730F6CDC-2C86-11D2-8773-92E220524153   Stobject.dll
     2C10A98F-D64F-43B4-BED6-DD0E1BF2074C   Vdt70.dll
     6F9F3481-84DD-4B14-B09C-6B4288ECCDE8   Vdt70.dll
     8E26BFC1-AFD6-11CF-BFFC-00AA003CFDFC   Vmhelper.dll
     F0975AFE-5C7F-11D2-8B74-00104B2AFB41   Wbemads.dll


      What about persistence?
       - Resurrect object properties from untrusted stream if control is SFI
       - Properties themselves may be COM objects
       - Read a CLSID from the stream, instantiate
68
      Killbit protection + persistence == NULL
       - Provide persistent stream with killbited CLSID / object embedded
       - ???
       - Profit

      Requirements and Limitations
       - ActiveX control must exist that is SFI
          • MSVidCTL
          • Flash
       - Control must take have a property of type XXX
       - Scriptable methods from IDispatch not reachable generally
       - IPersist* interfaces are reachable

      Demo


69
     CONCLUSION


70
      Interoperability has non-negligible security implications
       - Marshalling is hard
       - Controls interacting with each other create new attack capabilities

      Specific data management tasks give rise to unique bug classes
       - Object retention
       - Type Confusion
       - Extensions of trust

      Interoperability layers under-treated for security problems to date
       - Not just in browsers!

      Questions?



71

								
To top