WMI and Windows patches

novembre 13th, 2010 at 11:35 admin

Avant de lancer un exploit patché sur une machine Windows on préfère savoir à l’avance si la box est à jours ou non. Cela évite certaines mauvaises surprises et perte de temps à tester dans tous les sens un exploit codé par un chinois.

Comme vous le savez Microsoft édite ses patchs tous les seconds mardis de chaque mois. Le lendemain du patch tuesday est souvent consacré à differ (à l’aide de turbodiff ou de patchdiff2) les mises à jours. Après avoir localisé le bug et pondu un POC qui trigger la vuln on peut enfin coder quelque chose de plus sérieux :] En général un local EOP (Escalation Of Privilege) est le bienvenu.

Par la suite le jour arrive ou il s’agit de balancer notre exploit sur la machine cible. A ce moment on ressent la goute de sueur froide qui coule le long de notre dos parce que la loi du chaos peut tout foutre en l’air. L’un des paramètres qui décidera ou non de la réussite de notre attaque est bien sur le niveau de mise à jour de la machine.

Sous Windows XP connaitre les udpates présentes est plutôt simple. Il existe des outils dédiés comme WinUpdatesList de NirSoft En fonction des ‘KB’ installés on sait ou non si la machine est vulnérable.

Pour information WinUpdatesList va lire la clé de registre HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Hotfix.

Problème, sous Vista et 7 cette clé n’existe plus. On peut toujours passer par le menu ‘Installed Updates‘ mais c’est fastidieux si on doit vérifier beaucoup de patches.

Par chance Windows implémente WMI (Windows Management Instrumentation). Il s’agit en gros d’une interface standard d’échange d’information entre différentes applications. On peut la scripter avec du VBS et du PowerShell. Chose que seul news0ft sait faire ..

En interne Windows maintient un ensemble de classes contenant diverses informations sur le systèmes et ses applications regroupé sur une arborescence CIM (Common Information Model). Il est possible de voir l’ensemble de ces classes avec l’outil WMI Explorer.

Par exemple, si vous enregistrez le code suivant dans un .vbs et que l’exécutez il vous donnera les noms de tous les patches présents sur votre machine.

strComputer = "."
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colQuickFixes = objWMIService.ExecQuery("Select * from Win32_QuickFixEngineering")
For Each objQuickFix in colQuickFixes
    Wscript.Echo "Patch : " & objQuickFix.ServicePackInEffect
Next

La même chose est possible via l’outil en ligne de commande wmic. La commande ‘wmic QFE list full /format:htable’ vous sort un dump HTML des différents patches.

Remarquez que dans les 2 cas on a fait une requête sur la table Win32_QuickFixEngineering. La requête se présente sous la forme d’un langage de ‘query’ appelé WQL. En fait on récupère l’ensemble des instances de cette classe via un SELECT puis on énumère la property ServicePackInEffect de chaque objet.

Bien sur comme on préfère coder en C il existe une interface COM pour WMI. Pour l’utiliser il suffit d’instancier une instance de CLSID_WbemLocator afin se connecter et d’obtenir un objet IWbemServices. A partir de là on peut appeler la méthode ExecQuery avec du WQL pour récupérer ce qui nous intéresse.

Le code suivant est inspiré de l’exemple de la MSDN ‘Example: Creating a WMI Application‘ et permet de savoir si un patch est présent ou pas.

#define ANSI
#define _WIN32_DCOM
#define  _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <comdef.h>
#include <Wbemidl.h>
#include <stdio.h>
 
#pragma comment(lib, "wbemuuid.lib")
#pragma comment(lib, "comsuppw.lib")
 
BOOL IsKBInstalled(PCHAR Kb)
{
	BOOL Status=TRUE;
	HRESULT hres;
	IWbemLocator *pLoc=0;
        IWbemServices *pSvc=0;
        IEnumWbemClassObject* pEnumerator=NULL;
	IWbemClassObject *pclsObj;
	ULONG uReturn=0;
	VARIANT vtProp;
	CHAR Buffer[256];
	DWORD i=0;
 
    //Initialize COM
    hres=CoInitializeEx(0, COINIT_MULTITHREADED); 
    if(FAILED(hres))
    {
    	printf("[-] Error with CoInitializeEx : 0x%x\n", hres);
	goto end;
    }
 
    //Initialize 
    hres=CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE,NULL);
    if(FAILED(hres))
    {
    	printf("[-] Error with CoInitializeSecurity : 0x%x\n", hres);
    	CoUninitialize();
        goto end;
    }
 
    //Obtain the initial locator to Windows Management
    //on a particular host computer.
    hres=CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pLoc);
    if(FAILED(hres))
    {
    	printf("[-] Error with CoCreateInstance : 0x%x\n", hres);
		CoUninitialize();
		goto end;
    }
 
    // Connect to the root\cimv2 namespace with the
    // current user and obtain pointer pSvc
    // to make IWbemServices calls.
    hres=pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc);                              
    if(FAILED(hres))
    {
    	printf("[-] Error with ConnectServer : 0x%x\n", hres);
        pLoc->Release();     
        CoUninitialize();
        goto end;
    }
 
    // Set the IWbemServices proxy so that impersonation
    // of the user (client) occurs.
    hres=CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
    if(FAILED(hres))
    {
    	//printf("[-] Error with CoSetProxyBlanket : 0x%x\n", hres);
        pSvc->Release();
        pLoc->Release();     
        CoUninitialize();
        goto end;
    }
 
    // Use the IWbemServices pointer to make requests of WMI. 
    // Make requests here:
    _snprintf(Buffer, sizeof(Buffer)-1, "select * from Win32_QuickFixEngineering where ServicePackInEffect=\"KB%s\"", Kb);
    hres=pSvc->ExecQuery(bstr_t("WQL"), bstr_t(Buffer), WBEM_FLAG_FORWARD_ONLY|WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
    if(FAILED(hres))
    {
        pSvc->Release();
        pLoc->Release();     
        CoUninitialize();
        goto end;
    }
    else
    { 
    	i=0;
        while(pEnumerator)
        {
            hres=pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
            if(uReturn==0)
                break;
            // Get the value of the Name property
            hres=pclsObj->Get(L"ServicePackInEffect", 0, &vtProp, 0, 0);
            //wprintf(L"ServicePackInEffect: %s\n", vtProp.bstrVal);
            VariantClear(&vtProp);
            i++;
        }
    }
 
	if(i==0)
		Status=FALSE;
end:
    // Cleanup
    pSvc->Release();
    pLoc->Release();     
    CoUninitialize();
    return Status;
}
 
 
int __cdecl main(int argc, char *argv[])
{
	if(argc!=2)
	{
		printf("[-] Usage is : %s <KB patch number>\n", argv[0]);
		return 0;
	}
 
	printf("KB%s is %s\n", argv[1], IsKBInstalled(argv[1]) ? "present" : "not present");
}

Exemple avec le patch du mois d’octobre 2010 MS10-073 (KB981957).

C:\wmi.exe 981957
KB981957 is present

Maintenant vous pouvez ripper ce code et le mettre dans votre exploit qui pourra par lui même vérifier si le système est à jour sur 2000, XP, Vista et 7 :]

Code et binaire:
http://ivanlef0u.fr/repo/wmi.rar

Entry Filed under: C:

4 Comments

  • 1. Yannick  |  novembre 14th, 2010 at 02:15

    A noter aussi l’existence de WUA (qui me parait + developer friendly): http://msdn.microsoft.com/en-us/library/aa387099(v=VS.85).aspx


  • 2. admin  |  novembre 14th, 2010 at 15:36

    Note utiliser HotFixID au lieu de ServicePackInEffect http://pastebin.ca/1991109

    @Yannick aussi mais j’avais besoin d’un code qui tourne sur 2K pre-sp3 ;)


  • 3. lemul0t  |  janvier 16th, 2011 at 18:15

    Bel article, mais ya bien plus simple….
    sous xp comme sous seven :

    C:\systeminfo | findstr « KB982132″
    [63]: KB982132

    ;)


  • 4. FlUxIuS  |  juin 22nd, 2011 at 12:23

    Et pour le fun avec du Python :
    —————————————–
    import wmi
    c = wmi.WMI()
    wql = « Select * from Win32_QuickFixEngineering »
    for update in c.query(wql):
    print update
    —————————————–

    Résultat :
    instance of Win32_QuickFixEngineering
    {
    CSName = « CUIR-8F8484AE1A »;
    Description = «  »;
    FixComments = «  »;
    HotFixID = « File 1″;
    InstalledBy = «  »;
    InstalledOn = «  »;
    ServicePackInEffect = « KB898461″;
    };

    instance of Win32_QuickFixEngineering
    {
    ….


Trackback this post


Calendar

août 2017
L Ma Me J V S D
« fév    
 123456
78910111213
14151617181920
21222324252627
28293031  

Most Recent Posts