How to Verify the Validity of IIS Certificates on Remote Servers Using ABO

Nawal Kishore Gupta here. I am a developer on the Information Security Tools team focused on building host security assessment tools.

IIS: Admin Base Objects (ABO)

ABO is the most powerful way to control the IIS meta-base settings on different IIS Versions (above Windows 2000). Still using the ABO is a hidden art and very less technical document has been written on it.

One of the easy way is to read IIS Settings is read metabase.xml directly but this is not uniform in different version of IIS. Some of the confidential information has been moved to the registry. If you are developing a security or audit tool for IIS settings you must be interested in ABO.

Open Connection to ABO (IMSAdminBase Interface).

Creating a remote (DCOM) ABO connection is little tricky unless you know about DCOM. I am making it easy for you. Don’t forget to change the actual remote server name*.

 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
     //DCOM Object IMSAdminBase
     CComPtr <IMSAdminBase> pIAdminBase;
     IClassFactory * pcsfFactory = NULL; 
     COSERVERINFO csiMachineName; 
     ...

csiMachineName.pwszName = L”ServerName” ; //Change it*
     
     hr = CoGetClassObject(GETAdminBaseCLSID(TRUE), CLSCTX_SERVER, &csiMachineName,IID_IClassFactory, (void**) &pcsfFactory); 
     hr = pcsfFactory->CreateInstance(NULL, IID_IMSAdminBase, (void **) &pIAdminBase); 
Open Root Node Handle/Other Node Handle
 METADATA_HANDLE hMetaDataRoot=NULL;
METADATA_RECORD mdrRoot;
HRESULT hRes = pIAdminBase->OpenKey(METADATA_MASTER_ROOT_HANDLE, TEXT("/LM"),
     METADATA_PERMISSION_READ, 20, &hMetaDataRoot);
Read Node Property

Some of the key index name is not defined in ABO header files. You can use the following definitions.

 #define MD_SSL_CERT_HASH  5506
#define MD_SSL_STORE_NAME  5511

METADATA_RECORD-> dwMDIdentifier is the index of the property. You only need to change this index to read different properties of a node.  “W3SVC/1” is the path of first website. In this sample I am reading the SSL Store Name. Generally the output of this will be “MY” if the site is using SSL.

      BYTE buffer[BUFFER_LEN];
     DWORD dwReturnBufferSize=0;
     CString strStoreName;

     mdrRoot.dwMDAttributes = METADATA_NO_ATTRIBUTES;
     mdrRoot.dwMDUserType = IIS_MD_UT_SERVER;
     mdrRoot.dwMDDataType = ALL_METADATA;
     mdrRoot.dwMDDataLen = BUFFER_LEN;
     mdrRoot.pbMDData = buffer;
     mdrRoot.dwMDIdentifier = MD_SSL_STORE_NAME; // MD_SERVER_COMMENT or so          

     hRes = pIAdminBase->GetData(hMetaDataRoot, L"/W3SVC/1", &mdrRoot, &dwReturnBufferSize);

     if (hRes==S_OK)
     {
           strStoreName= (WCHAR*)mdrRoot.pbMDData;
     }
Read  Certificate Binary Hash Property

For reading the certificate hash dwMDIdentifier should be  set as  MD_SSL_CERT_HASH  and dwMDDataType should be set as BINARY_METADATA.

      BYTE binSSLHash[MAX_CERT_SIZE];
     DWORD dwBinHashSize;
     mdrRoot.dwMDAttributes = METADATA_NO_ATTRIBUTES;
     mdrRoot.dwMDUserType = IIS_MD_UT_SERVER;
     mdrRoot.dwMDDataType = BINARY_METADATA;
     mdrRoot.dwMDDataLen = MAX_CERT_SIZE;
     mdrRoot.pbMDData = (unsigned char *)&binSSLHash;
     mdrRoot.dwMDIdentifier = MD_SSL_CERT_HASH ; 
     //Read the first web site
     hRes = pIAdminBase->GetData(hMetaDataRoot,L"/W3SVC/1", &mdrRoot, &dwBinHashSize);           
     if (!SUCCEEDED(hRes))
     {
           return hRes;
     }
     dwBinHashSize=mdrRoot.dwMDDataLen;

Now we have both the SSLStoreName and SSLCertHash. We can use this values to read the certificate from certificate store which I will cover in my next blog post!