首页 > 代码库 > Windows Management Instrumentation WMI Security Technology Learning

Windows Management Instrumentation WMI Security Technology Learning

目录

0. 引言1. WMI(Windows Management Instrumentation)简介2. 基于WMI的攻击向量3. WMI编程示例

 

0. 引言

在进行服务器主机的入侵检测、安全攻防的研究中,常常会涉及到大量的和windows操作系统功能、资源、设备相关的操作(例如通过WMI COM API关闭FTP匿名登录等),而WMI提供了一个对windows操作系统底层各种异构模块/资源的统一接口,通过研究WMI(Windows Management Instruction)技术可以更加深入地了解如果通过API方式操作windows系统的基础服务

0x1: COM Component(COM组件)技术

因为WMI是架构在COM技术之上的,在开始学习WMI技术之前,我们先来学习一下windows中的COM Component组件技术

组件对象模型(Component Object Model COM),是微软的一套软件组件的二进制接口标准。这使得跨编程语言的进程间通信、动态对象创建成为可能。COM是多项微软技术与框架的基础,包括

1. OLE2. OLE自动化3. ActiveX4. COM+5. DCOM6. Windows shell7. DirectX8. Windows Runtime9. WMI..

什么是COM组件

1. COM组件是以WIN32动态链接库(DLL)、或可执行文件(EXE)形式发布的可执行代码组成,但要注意的是,COM组件不是DLL,只是利用DLL来给组件提供动态链接的能力2. COM组件是遵循COM规范编写的3. COM组件是一些小的二进制可执行文件4. COM组件可以给应用程序、操作系统以及其他组件提供服务5. 自定义的COM组件可以在运行时刻同其他组件连接起来构成某个应用程序6. COM组件可以动态的插入或卸出应用7. COM组件必须是动态链接的8. COM组件必须隐藏(封装)其内部实现细节9. COM组件必须将其实现的语言隐藏10. COM组件必须以二进制的形式发布11. COM组件必须可以在不妨碍已有用户的情况下被升级12. COM组件可以透明的在网络上被重新分配位置13. COM组件按照一种标准的方式来宣布它们的存在

Relevant Link:

http://freebird.blog.51cto.com/372076/184567/http://zh.wikipedia.org/wiki/%E7%BB%84%E4%BB%B6%E5%AF%B9%E8%B1%A1%E6%A8%A1%E5%9E%8Bhttp://baike.baidu.com/view/185316.htmhttp://www.cppblog.com/3522021224/archive/2007/06/22/26803.html

 

1. WMI(Windows Management Instrumentation)简介

Windows Management Instrumentation是用于提供共同的界面和对象模式以便访问

1. 操作系统2. 设备3. 应用程序4. 服务的管理信息

如果此服务被终止,多数基于 Windows 的软件将无法正常运行。如果此服务被禁用,任何依赖它的服务将无法启动,WMI是windows中的一个核心服务,它提供了一个标准的基础结构来监视和管理系统资源的服务

WMI是Microsoft实现的一个Web-Based Enterprise Management(WBEM)的执行方式,支持Distributed Management Task Force(DMTF),WMI提供您管理服务的能力

通过这张架构图,我们得到如下结论

1. WMI Providers And Managemed Object这是整个WMI体系的最底层,它对所有的"提供者(Provider)"提供了封装和抽象,包括    1.1 Native C/C++ Provider COM object     A WMI provider is a COM object that monitors one or more "managed objects" for WMI. A "managed object" is a logical or physical enterprise component, such as a hard disk drive,
network adapter, database system, operating system, process, or service.
1) SNMP WMI Provider: SNMP Managed Entity 2) Cimv2 WMI Provider: Windows(Win32) Managed Entity 3) Security Provider: Retrieves or changes security settings that control ownership, auditing, and access rights to files, directories, and shares .... 4) Any Managed Entity(Native Code) Similar to a driver, a provider supplies WMI with data from a managed object and handles messages from WMI to the managed object. WMI providers consist of a DLL file and a
Managed Object Format (MOF) file that defines the classes for which the provider returns data and performs operations. Providers, like WMI C++ applications, use the COM API for
WMI.
1.2 .NET C#、VB.NET、And so on COM Inter-Op 1) .NET Managed Application/Entity2. WMI InfrastructureThe WMI infrastructure is a Microsoft Windows operating system component 2.1 WMI Core(CIM Object Managedr) 2.2 WMI Repository WMI repository is organized by WMI namespaces,WMI的namespace由系统自身创建和Provider创建2部分组成,例如 1) root\default 2) root\cimv2 3) root\subscription ... 由底层的Provider创建的namespace 4) /LM/MSFTPSVC/n .. The WMI service acts as an intermediary between the providers, management applications, and the WMI repository. Only static data about objects is stored in the repository,
such as the classes defined by providers. WMI obtains most data dynamically from the provider when a client requests it. You also can set up subscriptions to receive event
notifications from a provider简单来说,WMI Repository就相当于一个保存WMI信息的数据库,而底层的Provider所提供的信息就相当于一个个独立的数据表,在WMI中称之为命名空间namespace,我们在进行WMI查询之前,需要明确指定需要查询的namespace3. WMI Consumers(Management Applications)A WMI consumer is a management application or script that interacts with the WMI infrastructure. A management application can query, enumerate data, run provider methods, or
subscribe to events by calling either the "COM API" for WMI or the Scripting API for WMI. The only data or actions available for a managed object, such as a disk drive or a
service, are those that a provider supplies.这一层是程序员能直接接触到的API层面的东西,我们可以使用C
++、WMI Script脚本编写代码去操作WMI COM API对WMI进行操作 3.1 C/C++ Client 3.2 Scripts 3.3 .NET Client Application
关于WMI COM API接口的相关信息,请参阅
http://msdn.microsoft.com/en-us/library/aa389276(v=vs.85).aspx

关于Scripting API for WMI接口的相关信息,请参阅(Scripting API For WMI本质上还是调用的COM API)
http://msdn.microsoft.com/en-us/library/aa393258(v=vs.85).aspx

0x1: WMI的功能

1. Windows管理规范(Windows Management Instrumentation)是一项核心的 Windows 管理技术2. 用户可以使用 WMI 管理本地和远程计算机3. WMI 通过编程和脚本语言为日常管理提供了一条连续一致的途径。例如,用户可以:    1) 在远程计算机器上启动一个进程     2) 设定一个在特定日期和时间运行的进程     3) 远程启动计算机。    4) 获得本地或远程计算机的已安装程序列表。    5) 查询本地或远程计算机的 Windows 事件日志 

Relevant Link:

http://blog.csdn.net/wzsy/article/details/1632792http://msdn.microsoft.com/zh-cn/library/aa394553(v=vs.85).aspxhttp://msdn.microsoft.com/en-us/library/aa394570(v=vs.85).aspxhttp://msdn.microsoft.com/zh-cn/library/aa393964(v=vs.85).aspxhttp://msdn.microsoft.com/zh-cn/library/aa394582(v=vs.85).aspxhttp://blog.itpub.net/7868752/viewspace-1056801/

 

2. 基于WMI的攻击向量

WMI(Windows管理规范)作为一项Windows管理技术,方便用户对计算机进行远程管理。但是它的易用性也导致了系统的安全性大幅下降。让用户的电脑除了自己账号密码的保护外再没有什么安全保护措施

我们接下来一起学习一下黑客是如何通过WMI技术对操作系统进行攻击的

0x1: 漏洞风险的起因

从WMI本质的功能看,它是为了让计算机的管理更容易,同时方便管理员远程操作系统而产生的,一般情况下,在本地计算机上执行的WMI操作也可以在远程计算机上执行,只要用户拥有该计算机的管理员权限
如果用户对远程计算机拥有权限并且远程计算机支持远程访问,那么用户就可以连接到该远程计算机并执行拥有相应权限的操作

因此,WMI能够成为远程控制下的一个"合法通道",有了这个通道,入侵者不需要对自己进行伪装,不必再为探测出对方账号的密码为空后,找不到连接对方系统的通道而发愁。
从安全攻防的角度来看,这就是一个典型的接口安全问题,一个原本是正常提供功能的接口因为没有进行必要的访问权限、使用权限的控制而导致"接口滥用",从而给了黑客可乘之机

0x2: 黑客可能采用的攻击方式

前面介绍了WMI的原理,下面我们实际了解下,如何通过WMI进行入侵,我们知道WMI是windows操作系统中的一个比较基础的服务,默认情况下操作系统都会开启这个服务端口的,即这条"WMI入侵通道"相对来说是比较畅通的,对黑客来说,它所需要的就是通过其他的途径获得一个可以登录系统的帐号、密码

1. 扫描135端口要寻找可以通过WMI入侵的远程计算机,只要对135端口进行扫描就可以了。因为WMI服务默认打开的就是135端口。例如可以采用NTscan扫描工具,因为它不但可以对IPC$、SMB、WMI这些信息进行扫描,同时还可以对扫描到的远程账户
进行弱口令猜测,功能相对来说比较强大。
2. 运行NTscan,在程序窗口的"配置"区域中进行设置。首先在"起始IP""结束"选项中输入扫描的IP地址范围,接着选择"WMI扫描"选项,并且在"扫描打开端口的主机"选项后输入"135",最后点击"开始"按钮就开始进行扫描 3. 开启终端服务找到可以入侵的远程计算机以后,就可以开始入侵操作了。首先是开启终端服务(Terminal Service) 要注意的是,通过WMI通道执行系统指令需要我们提供一对可能登录系统的帐号密码(这是这种攻击姿势的关键)

0x3: 如何防御WMI入侵

我们知道,攻防是一种针锋相对的技术,通过研究黑客在攻击时所采用的攻击向量的关键点,在这个关键点上进行过滤、或者阻断从而达到防御的目的

1. 屏闭135端口防御入侵从WMI入侵的过程中我们可以看出,整个过程中使用的端口都是135。所以为了防止别人通过WMI进行入侵,我们可以使用防火墙对135端口进行屏蔽,这样就可以达到防范类似的入侵。用户加强自己的账号密码强度,也可以有效防范入侵2. 加强帐号安全管理从本质上讲,WMI是一个正常的功能通道,WMI本身并不是漏洞,产生漏洞的是系统帐号的泄漏,导致黑客滥用这个通道进行高危指令的执行,所以,我们可以从问题的源头入手,部署高强度密码策略,定期更换密码等措施解决问题

Relevant Link:

http://blog.itpub.net/7868752/viewspace-1056801/

 

3. WMI编程示例

操作WMI的方式有以下几种方式

1. Scripts written in Microsoft ActiveX script hosting, including Visual Basic Scripting Edition (VBScript) and Perl2. Windows PowerShell3. Visual Basic applications4. Active Server Pages5. C++ applications6. .NET Framework applications written in C#, Visual Basic .NET, or J#

不论采用哪种方式,对WMI的操作都必须完成以下几个基本步骤

1. Obtaining Data from WMI:从WMI获取数据    1) Decide which language to use    2) Ensure that your connections to remote computers work    3) Connecting to WMI on remote computers requires the correct security settings    4) After connecting to WMI, you can obtain data through queries and enumerations.    5) Registry data is available through WMI and you can create new keys and values or modify existing ones    6) You can subscribe to event notifications through WMI, either temporarily between system reboots or permanently.    7) Performance counter data for a system is available through WMI.2. Providing Data to WMIDecide on the type of provider to write. you can take several other approaches to writing a WMI COM provider:    1) Using the WMI ATL Wizard in Visual Studio.    2) Using COM directly in any integrated development environment.    3) Using WMI in the .NET Framework to create a managed code provider.    4) Using the provider framework classes is not recommended.3. Important Tasks for WMI    1) WMI Tasks for Scripts and Applications    2) Creating a WMI Application or Script    3) Connecting to WMI on a Remote Computer    4) Connecting to WMI on a Remote Computer by Using Windows PowerShell    5) Monitoring Events    6) Providing Data to WMI    7) Getting and Providing Data on a 64-bit Computer

这里我们以最常用的C++、VBS Scripts方式进行编程学习

0x1: C++ applications

// wmi_getsysinfo.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>#include <comdef.h>#include <Wbemidl.h># pragma comment(lib, "wbemuuid.lib")using namespace std;int _tmain(int argc, _TCHAR* argv[]){    HRESULT hres;    /*    Initialize COM.    由于用C++编写WMI应用是基于COM技术的,所以必须初始化COM库     */    hres =  CoInitializeEx(0, COINIT_MULTITHREADED);     if (FAILED(hres))    {        cout << "Failed to initialize COM library. "             << "Error code = 0x"             << hex << hres << endl;        return 1;              // Program has failed.    }    /*    Initialize    初始化COM库安全级别    */    hres =  CoInitializeSecurity(        NULL,             -1,      // COM negotiates service                          NULL,    // Authentication services        NULL,    // Reserved        RPC_C_AUTHN_LEVEL_DEFAULT,    // authentication        RPC_C_IMP_LEVEL_IMPERSONATE,  // Impersonation        NULL,             // Authentication info         EOAC_NONE,        // Additional capabilities        NULL              // Reserved        );    if (FAILED(hres))    {        cout << "Failed to initialize security. "             << "Error code = 0x"             << hex << hres << endl;        CoUninitialize();        return 1;          // Program has failed.    }    // Obtain the initial locator to Windows Management    // on a particular host computer.    IWbemLocator *pLoc = 0;    /*    连接到WMI命名空间    通过调用CoCreateInstance初始化WMI的定位器(IWbemLocator类型的实例)    */    hres = CoCreateInstance(        CLSID_WbemLocator,                     0,         CLSCTX_INPROC_SERVER,         IID_IWbemLocator, (LPVOID *) &pLoc);    if (FAILED(hres))    {        cout << "Failed to create IWbemLocator object. "            << "Error code = 0x"            << hex << hres << endl;        CoUninitialize();        return 1;       // Program has failed.    }    IWbemServices *pSvc = 0;    // Connect to the root\cimv2 namespace with the    // current user and obtain pointer pSvc    // to make IWbemServices calls.    /*    调用IWbemLocator::ConnectServer方法,通过这个定位器连接到WMI的命名空间,通过把一个IWbemServices的实例以参数形式传递给ConnectServer方法,就会创建这个服务。如我们需要一些BIOS信息,那么需要使用的WMI提供程序是Win32_BIOS,则需要连接到ROOT//CIMV2命名空间中。    */    hres = pLoc->ConnectServer(        _bstr_t(L"ROOT\\CIMV2"), // WMI namespace        NULL,                    // User name        NULL,                    // User password        0,                       // Locale        NULL,                    // Security flags                         0,                       // Authority               0,                       // Context object        &pSvc                    // IWbemServices proxy        );                                if (FAILED(hres))    {        cout << "Could not connect. Error code = 0x"             << hex << hres << endl;        pLoc->Release();             CoUninitialize();        return 1;                // Program has failed.    }    cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;    // Set the IWbemServices proxy so that impersonation    // of the user (client) occurs.    /*    设置WMI服务的安全级别    根据上一步得到的服务,设置相应的服务安全级别。通常来说,如果我们没有设置适当的安全属性,COM安全方案不允许一个进程去访问另一个进程,因此如果我们要访问一个外部进程的对象,那么我们应该设置适当的IWbemServices的安全级别。    */    hres = CoSetProxyBlanket(        pSvc,                         // the proxy to set        RPC_C_AUTHN_WINNT,            // authentication service        RPC_C_AUTHZ_NONE,             // authorization service        NULL,                         // Server principal name        RPC_C_AUTHN_LEVEL_CALL,       // authentication level        RPC_C_IMP_LEVEL_IMPERSONATE,  // impersonation level        NULL,                         // client identity         EOAC_NONE                     // proxy capabilities             );    if (FAILED(hres))    {        cout << "Could not set proxy blanket. Error code = 0x"             << hex << hres << endl;        pSvc->Release();        pLoc->Release();             CoUninitialize();        return 1;               // Program has failed.    }    //通过WQL使用WMI服务    IEnumWbemClassObject* pEnumerator = NULL;    hres = pSvc->ExecQuery(        bstr_t("WQL"),         bstr_t("SELECT * FROM Win32_OperatingSystem"),        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,         NULL,        &pEnumerator);    if (FAILED(hres))    {        cout << "Query for processes failed. "            << "Error code = 0x"             << hex << hres << endl;        pSvc->Release();        pLoc->Release();             CoUninitialize();        return 1;               // Program has failed.    }    else    {         IWbemClassObject *pclsObj;        ULONG uReturn = 0;        while (pEnumerator)        {            hres = pEnumerator->Next(WBEM_INFINITE, 1,                 &pclsObj, &uReturn);            if(0 == uReturn)            {                break;            }            VARIANT vtProp;            // Get the value of the Name property            hres = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);            wcout << "Manufacturer Name : " << vtProp.bstrVal << endl;            VariantClear(&vtProp);        }    }    // Cleanup    // ========    pSvc->Release();    pLoc->Release();         CoUninitialize();     return 0;}

0x2: Scripts written in Microsoft ActiveX script hosting

 Check command line parametersSelect Case WScript.Arguments.Count    Case 0         Default if none specified is local computer (".")        Set objWMIService = GetObject( "winmgmts://./root/cimv2" )        Set colItems = objWMIService.ExecQuery( "Select * from Win32_ComputerSystem", , 48 )        For Each objItem in colItems            strComputer = objItem.Name        Next    Case 1         Command line parameter can either be a computer name         or "/?" to request online help        strComputer = Wscript.Arguments(0)        if InStr( strComputer, "?" ) > 0 Then Syntax    Case Else         Maximum is 1 command line parameter        SyntaxEnd SelectOn Error Resume Next Connect to computers WMI serviceSet objWMIService = GetObject( "winmgmts://" & strComputer & "/root/cimv2" ) Display error number and description if applicableIf Err.Number Then ShowError() Collect BIOS informationSet colItems = objWMIService.ExecQuery( "Select * from Win32_BIOS where PrimaryBIOS = true", , 48 ) Display error number and description if applicableIf Err.Number Then ShowError() Initialize screen output variablestrMsg = vbCrLf & "BIOS summary for " & strComputer & ":" & vbCrLf Prepare collected info for displayFor Each objItem in colItems    strMsg = strMsg _           & "    BIOS Name       :  " & objItem.Name & vbCrLf _           & "    Version         :  " & objItem.Version & vbCrLf _           & "    Manufacturer    :  " & objItem.Manufacturer & vbCrLf _           & "    SMBIOS Version  :  " & objItem.SMBIOSBIOSVersion & vbCrLfNext Display the resultsWScript.Echo strMsg DoneWScript.Quit(0)Sub ShowError    strMsg = vbCrLf & "Error # " & Err.Number & vbCrLf & _             Err.Description & vbCrLf & vbCrLf    SyntaxEnd SubSub Syntax    strMsg = strMsg & vbCrLf & "BIOS.vbs,  Version 1.00" & vbCrLf & _             "Display BIOS information." & vbCrLf & vbCrLf & _             "Usage:  CSCRIPT  BIOS.VBS  [ computer_name ]" & _             vbCrLf & vbCrLf & _             "Where:  " & Chr(34) & "computer_name" & Chr(34) & _             " is the name of a WMI enabled computer on the network" & _             vbCrLf & vbCrLf & _             "Written by Rob van der Woude" & vbCrLf & _             "http://www.robvanderwoude.com" & vbCrLf & vbCrLf & _             "Created using Microsoft‘s Scriptomatic tool" & vbCrLf & _             "http://www.microsoft.com/technet/treeview/default.asp?" & _             "url=/technet/scriptcenter/WMImatic.asp" & vbCrLf    WScript.Echo strMsg     Abort with return code 1    WScript.Quit(1)End Sub

Relevant Link:

http://msdn.microsoft.com/en-us/library/aa390418(v=vs.85).aspxhttp://www.robvanderwoude.com/wmiexamples.phphttp://www.codeproject.com/Articles/46390/WMI-Query-Language-by-Example

 

Copyright (c) 2014 LittleHann All rights reserved

 

Windows Management Instrumentation WMI Security Technology Learning